Spring事务使用有两种方式:声明式事务(如通过@Transactional实现注解方式或者xml配置方式)和编程式事务方式,优缺点如下:
- 声明式事务:通过注解和xml配置使开发者只关注业务开发,而不需要关注事务的提交和回滚,但最小粒度在方法上,不能对一块代码增加事务,另外也要考虑事务嵌套带来的副作用(比如长事务)。
- 编程式事务:比较灵活,需要开发者在代码中手动的管理事务的开启、提交、回滚等操作,但若对事务理解不够深刻,容易出错。
这里重点讲编程式事务方式使用的案例和注意点,使用方式如下:
private void executeTransactional(HelpParticipationContextDTO contextDTO) {
return transactionTemplate.execute(action -> {
// 1.插入用户信息
int row = insertStudent();
if(row <= 0) {
throw new RuntimeException("插入失败");
}
// 2.更新统计信息
updateStatistics(contextDTO);
return true;
});
}
默认场景下若业务处理过程中出现RuntimeException或者Error异常就会回滚,详细参考org.springframework.transaction.support.TransactionTemplate-execute方法实现,还有一种实现方式如下:
private void executeTransactional(HelpParticipationContextDTO contextDTO) {
return transactionTemplate.execute(action -> {
try {
// 1.插入用户信息
int row = insertStudent();
if(row <= 0) {
throw new RuntimeException("插入失败");
}
// 2.更新统计信息
updateStatistics(contextDTO);
return true;
} catch (Exception e) {
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
// status.setRollbackOnly();
return false;
}
});
}
这种方式只是把当前事务标记为回滚,当事务进行提交时发现该事务已经设置了回滚标记,则对当前事务进行回滚,这里要看提交事务的源代码,如下:
// org.springframework.transaction.support.AbstractPlatformTransactionManager-commit
public final void commit(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
// 这里就会判断事务的回滚标记
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
processRollback(defStatus, false);
return;
}
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
processRollback(defStatus, true);
return;
}
processCommit(defStatus);
}
总结一下,当业务出现了RuntimeException或者Error异常,Spring事务进行回滚,另外编程式事务对代码控制比较灵活,但是建立在对Spring事务原理理解的基础上(上面总结了编程式事务使用的两种方式)。