【问题标题】:How to handle manually transactions while using jdbcTemplate?使用 jdbcTemplate 时如何手动处理事务?
【发布时间】:2020-02-06 06:25:16
【问题描述】:

我有一个具有“解释器 SQL”功能的网络应用程序。用户可以编写一些命令并执行它。

例如,用户想要执行 3x 操作:

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 中,它们在循环中一个接一个地执行。
例如,如果我有那个循环:

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()
}

【问题讨论】:

  • 根据您的数据库,DDL 语句可能是事务性的,但通常不是。我知道 Postgres 确实支持这一点,但 Oracle 不支持。所以YMMV。
  • 使用的数据库是什么? PostgreSQL ? mysql ?如果是 MySQL,引擎是什么? (InnoDb,MyIsam)
  • 甲骨文............

标签: java spring hibernate jdbctemplate


【解决方案1】:

@Transactional注释你的方法,如果你从你的类外调用它,它只会在所有操作都成功的情况下提交

描述单个方法或类的事务属性

阅读更多Understanding the Spring Framework’s declarative transaction implementation

仅仅告诉您使用@Transactional 注释来注释您的类,将@EnableTransactionManagement 添加到您的配置中,然后期望您了解它的工作原理是不够的

【讨论】:

  • 好吧,我试过@Transactional (org.springframework.transaction.annotation) 但它不起作用。无论我是否添加@Transactional,我的方法总是提交所有内容:(
  • @Brarord 你需要定义自动提交为false,或者在stackoverflow.com/questions/17224887/…查看答案
【解决方案2】:

您可以尝试类似的方法。

@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
    }
}

只有在从其他 bean 调用方法时才会起作用。

【讨论】:

  • 没有效果 :( 我的查询已提交 :(
  • imgur.com/zMN6uIY 该方法的结果,将 rollbackOnly 更改为 true 后,没有任何反应,一切都已提交。
  • 你是否从其他bean调用事务方法?还是来自班级?
  • 对不起,我不知道你到底在问什么? (聂 rozumiem pytania :
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-11
  • 1970-01-01
  • 1970-01-01
  • 2015-01-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多