默认 spring 事务只在发生未被捕获的 RuntimeExcetpion 时才会回滚。
- 类似这样的方法不会回滚:
if(userSave) {
try {
userDao.save(user);
userCapabilityQuotaDao.save(capabilityQuota);
} catch (Exception e) {
logger.info("能力开通接口,开户异常,异常信息:" + e);
}
}
- 下面的方法会回滚:
if(userSave) {
try {
userDao.save(user);
userCapabilityQuotaDao.save(capabilityQuota);
} catch (Exception e) {
logger.info("能力开通接口,开户异常,异常信息:" + e);
throw new RuntimeException();
}
}
或者
if(userSave) {
try {
userDao.save(user);
userCapabilityQuotaDao.save(capabilityQuota);
} catch (Exception e) {
logger.info("能力开通接口,开户异常,异常信息:" + e);
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
spring aop 异常捕获原理
被拦截的方法需显式抛出异常,并不能经任何处理,这样 aop 代理才能捕获到方法的异常,才能进行回滚,默认情况下 aop 只捕获 RuntimeException 的异常,但可以通过配置来捕获特定的异常并回滚。
换句话说在 service 的方法中不使用 try{}catch{}
或者在 catch 中最后加上 throw new RuntimeExcetpion();
,这样程序异常时才能被 aop 捕获进而回滚。
解决方案:
- 例如:service 层处理事务,那么 service 中的方法中不做异常捕获,或者在 catch 语句中最后增加
throw new RuntimeException()
语句,以便让 aop 捕获异常再去回滚,并且在 service 上层(controller 层)要继续捕获这个异常并处理。 - 在 service 层方法的 catch 语句中增加:
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
手动回滚,这样上层就无需去处理异常。