问题
在看《Spring揭秘》事务章节内容,调试代码过程中,出现以下异常:
19/01/29 14:41:31 [main]: DEBUG datasource.DataSourceTransactionManager: Creating new transaction with name [ChansonTransaction]: PROPAGATION_REQUIRES_NEW,ISOLATION_READ_COMMITTED
19/01/29 14:41:31 [main]: DEBUG datasource.DataSourceTransactionManager: Acquired Connection [jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=UTF-8&useSSL=false, UserName=root@localhost, MySQL Connector Java] for JDBC transaction
19/01/29 14:41:31 [main]: DEBUG datasource.DataSourceUtils: Changing isolation level of JDBC Connection [jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=UTF-8&useSSL=false, UserName=root@localhost, MySQL Connector Java] to 2
19/01/29 14:41:31 [main]: DEBUG datasource.DataSourceTransactionManager: Switching JDBC Connection [jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=UTF-8&useSSL=false, UserName=root@localhost, MySQL Connector Java] to manual commit
19/01/29 14:41:31 [main]: DEBUG core.JdbcTemplate: Executing prepared SQL update
19/01/29 14:41:31 [main]: DEBUG core.JdbcTemplate: Executing prepared SQL statement [UPDATE t_user SET password=? WHERE user_name =?]
19/01/29 14:41:31 [main]: DEBUG core.JdbcTemplate: SQL update affected 1 rows
19/01/29 14:41:31 [main]: DEBUG datasource.DataSourceTransactionManager: Initiating transaction rollback
19/01/29 14:41:31 [main]: DEBUG datasource.DataSourceTransactionManager: Rolling back JDBC transaction on Connection [jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=UTF-8&useSSL=false, UserName=root@localhost, MySQL Connector Java]
19/01/29 14:41:31 [main]: DEBUG datasource.DataSourceUtils: Resetting isolation level of JDBC Connection [jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=UTF-8&useSSL=false, UserName=root@localhost, MySQL Connector Java] to 4
19/01/29 14:41:31 [main]: DEBUG datasource.DataSourceTransactionManager: Releasing JDBC Connection [jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=UTF-8&useSSL=false, UserName=root@localhost, MySQL Connector Java] after transaction
19/01/29 14:41:31 [main]: DEBUG datasource.DataSourceUtils: Returning JDBC Connection to DataSource
Exception in thread "main" org.springframework.transaction.IllegalTransactionStateException: Transaction is already completed - do not call commit or rollback more than once per transaction
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:697)
at springjiemi.platformtransaction.UserService.update(UserService.java:42)
at springjiemi.platformtransaction.UserService.main(UserService.java:50)
分析
日志显示存在事务多次提交的问题。
分析了一下源代码:
public void update(String userName) {
DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
transactionDefinition.setName("ChansonTransaction");
//默认:TransactionDefinition.ISOLATION_DEFAULT
transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
//默认:TransactionDefinition.PROPAGATION_REQUIRED
transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus txStatus = platformTransactionManager.getTransaction(transactionDefinition);
try {
userDao1.doDataAccess(userName);
int i = 9/0;
userDao2.doDataAccess(userName);
} catch (DataAccessException e) {
platformTransactionManager.rollback(txStatus);
} catch (Exception e) {
platformTransactionManager.rollback(txStatus);
}
platformTransactionManager.commit(txStatus);
}
由于异常被catch,而在catch时,进行了事务回滚,正常在此应该退出方法处理(程序直接返回或者抛出异常),但事实上程序直接执行了后续的代码:platformTransactionManager.commit(txStatus);所以报错。
解决
解决方法:在catch过程中,抛出异常,结束方法执行。
public void update(String userName) {
DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
transactionDefinition.setName("ChansonTransaction");
//默认:TransactionDefinition.ISOLATION_DEFAULT
transactionDefinition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
//默认:TransactionDefinition.PROPAGATION_REQUIRED
transactionDefinition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
TransactionStatus txStatus = platformTransactionManager.getTransaction(transactionDefinition);
try {
userDao1.doDataAccess(userName);
int i = 9/0;
userDao2.doDataAccess(userName);
} catch (DataAccessException e) {
platformTransactionManager.rollback(txStatus);
throw e;
} catch (Exception e) {
platformTransactionManager.rollback(txStatus);
throw e;
}
platformTransactionManager.commit(txStatus);
}
文章结束。