如何在使用jdbcTemplate时手动处理事务?
如何在使用jdbcTemplate时手动处理事务?
我有一个具有“SQL解释器”功能的Web应用程序。用户可以编写一些命令并执行它。例如,用户想要执行3个操作:
1. 将"aaab"表的"WHATEVER"重命名为"Something";
2. 将"aaab"表的"RESOURCES"重命名为"SomethingElse";
3. 修改"aaab"表的"EXAMCATEGORIES"的"NAME"字段为"NUMBER";
我想要实现的目标是:
1. 如果操作1、2、3都成功,则提交所有3个操作。
2. 如果操作1、2成功但3失败,则回滚所有3个操作。
通常,如果列表中的任何一个操作不成功,则我想回滚所有操作。
以下是我的解释器代码:
public ArrayList
ArrayList
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){
...begin()
for(int i = 0; i < queryRows.length; ++i){
// statements are executed there one after another.
}
if(myCondition)
...commit()
else
...rollback()
}
在使用jdbcTemplate时,手动处理事务可能会遇到一些问题。在上述代码中,class X中的executeSQL方法中,事务的开始和提交被正确地放置在了代码的适当位置。但是,如果在同一个类中的另一个方法(test方法)中调用executeSQL方法,事务将无法正常工作。
为了解决这个问题,可以将调用executeSQL方法的代码移到另一个类中(class Y),并在该类中调用executeSQL方法。这样做可以确保事务能够正常工作。
然而,即使将调用方法移动到其他类中,仍然可能会遇到问题。在上述代码中,当将rollbackOnly设置为true时,事务并没有回滚,而是继续提交。这可能是因为事务管理器可能已经在之前的代码执行过程中进行了提交。
因此,为了确保事务能够正确回滚,建议在调用executeSQL方法时,确保该方法是从其他bean中调用的,而不是在同一个类中调用。这样可以确保事务能够正常工作,并在需要时回滚。
总结起来,处理手动事务时,可以遵循以下步骤:
1. 将事务的开始和提交放置在代码的适当位置。
2. 确保调用事务方法的代码是从其他bean中调用的,而不是在同一个类中调用。
3. 确保事务管理器没有在之前的代码执行过程中进行过提交,以确保事务能够正确回滚。
通过遵循上述步骤,可以正确处理手动事务,并确保事务能够按预期工作。
在使用jdbcTemplate时,如果需要手动处理事务,可以通过在方法上使用@Transactional注解来实现。使用该注解后,只有在所有操作都成功的情况下才会提交事务,如果从类外调用该方法,则需要手动提交事务。
不过,仅仅使用注解是不够的,还需要在配置中添加相应的配置。具体实现方式可参考Spring框架文档中的"Understanding the Spring Framework’s declarative transaction implementation"一节。
有用户尝试了使用org.springframework.transaction.annotation注解,但并未生效。无论是否添加注解,方法都会自动提交事务。这个问题可以通过在配置中设置auto commit为false来解决,或者参考stackoverflow上的相关答案。