Как обрабатывать транзакции вручную при использовании jdbcTemplate? - PullRequest
0 голосов
/ 06 февраля 2020

У меня есть веб-приложение, которое имеет функцию «интерпретатор SQL». Пользователь может написать несколько команд и выполнить их.

Например, пользователь хочет выполнить 3 операции:

1.  ALTER TABLE "aaab".WHATEVER RENAME TO "Something";
2.  ALTER TABLE "aaab".RESOURCES RENAME TO "SomethingElse";
3.  ALTER TABLE "aaab".EXAMCATEGORIES MODIFY NAME NUMBER;

Чего я хочу достичь:

  1. Если операция 1, 2, 3 тогда был успешным commit все 3x операции
  2. Если операция 1, 2 была успешной, но 3 не была успешной, тогда rollback все 3x операции

Обычно, если any операция из списка не удалась, тогда я хочу rollback все операции.


Итак, вот мой переводчик:

public ArrayList<String> executeSQL(String[] queryRows) {
    ArrayList<String> listException = new ArrayList<String>();
    for (int i = 0; i < queryRows.length; ++i) {
        String query = queryRows[i];
        if(query.trim().length() > 5 && query.trim().substring(0, 6).toUpperCase().equals("SELECT")){
            try{
                mapList = jdbcTemplate.queryForList(query);
                int rows = mapList.size();
                listException.add("Success! { affected rows --> [" + rows + "] }");
                updateFlag = true;
            }catch (DataAccessException exceptionSelect){
                listException.add(exceptionSelect.getCause().getMessage());
                updateFlag = false;
                break;
            }
        }
        else if(whatKindOfStatementIsThat(query,"DDL")){
            try{
                jdbcTemplate.execute(query);
                listException.add("Success!");
                updateFlag = true;
            }catch (DataAccessException exceptionDDL){
                listException.add(exceptionDDL.getCause().getMessage());
                updateFlag = false;
                break;
            }
        }
        else if (whatKindOfStatementIsThat(query,"DML")){
            try {
                int rows = jdbcTemplate.update(query);
                listException.add("Success! { zaafektowane wiersze --> [" + rows + "] }");
                updateFlag = true;
            }catch (DataAccessException exceptionDML){
                listException.add(exceptionDML.getCause().getMessage());
                updateFlag = false;
                break;
            }
        }
        else{
            try{
                jdbcTemplate.execute(query);
                listException.add("Success!");
                updateFlag = true;
            }catch (Exception exception){
                listException.add(exception.getCause().getMessage());
                updateFlag = false;
                break;
            }
        }
    }
    return listException;
}

Это действительно просто, во-первых, я проверяю, какое заявление было введено.
1. Если оператор - select, тогда мне нужен список результатов mapList = jdbcTemplate.queryForList(query);
2. Если оператор - DDL, тогда мне ничего не нужно jdbcTemplate.execute(query);
3. Если оператор - DML тогда мне нужно количество затронутых строк int rows = jdbcTemplate.update(query);
4. Все остальное, просто выполните собственный запрос jdbcTemplate.execute(query);

Я храню свои операторы внутри ArrayList, и они выполняются одна за другой в l oop.
Так, например, если у меня есть это l oop:

public void executeSQL (String[] queryRows){ 
     for(int i = 0; i < queryRows.length; ++i){
          // statements are executed there one after another.
     }
}

Как мне добиться чего-то подобного?

public void executeSQL(String[] queryRows){ 
     ...begin()
     for(int i = 0; i < queryRows.length; ++i){
          // statements are executed there one after another.
     }
     if(myCondition)
          ...commit()
     else
          ...rollback()
}

Ответы [ 2 ]

1 голос
/ 06 февраля 2020

Вы можете попробовать что-то подобное.

@Component
class X {
    @Transactional
    public void executeSQL(String[] queryRows){ 
         ...begin()
         for(int i = 0; i < queryRows.length; ++i){
              // statements are executed there one after another.
         }
         if(myCondition)
              ...commit()
         else
              throw new RuntimeException(); //or any other exception
              //or TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); (not recomended).

    }

    public void test(){
       executeSQ(...);// won't work
    }
}

@Component
class Y {
    @Autowired
    X x;

    public void test(){
       x.executeSQ(...);//should work
    }
}

Это будет работать, только если метод вызывается из другого компонента.

1 голос
/ 06 февраля 2020

Аннотируйте ваш метод с помощью @ Transactional , и он будет фиксироваться, только если все операции будут выполнены успешно, если вы вызовете его извне вашего класса

Описывает атрибут транзакции для отдельного метода или для класса

Подробнее в Понимание реализации декларативной транзакции Spring Framework

Недостаточно просто сказать, что вы аннотируете свои классы с аннотацией @Transactional добавьте @EnableTransactionManagement в свою конфигурацию и ожидайте, что вы поймете, как все это работает

...