spring @Transaction事务回滚失败
今天客户提出一个新问题,出库一批商品,提示失败了,但是库存数量却减少了。看了一下代码一头雾水,我们的代码加了事物,且捕获异常。
经过调试代码发现就是两个原因导致的
第一、在当前方法的catch中处理了捕获的异常,没有向上抛出异常,事务不能回滚
分析:
1.在java中异常的基类为throwable,他有两个子类exception与errors,同时runtimeexception就是exception的子类;
2.runtimeexception,即运行时异常,为非受检(unchecked)异常;
3.exception的其他子类异常,为非运行时异常,为受检异常(checked)异常;
spring事务回滚机制是这样的:当所拦截的方法有指定异常抛出,事务才会自动进行回滚!
①被拦截方法-—— 注解式:方法或者方法所在类被@transactional注解;
②异常—— 该方法的执行过程必须出现异常,这样事务管理器才能被触发,并对此做出处理;
③指定异常—— 默认配置下,事务只会对error与runtimeexception及其子类这些unchecked异常,做出回滚。一般的exception这些checked异常不会发生回滚(如果一般exception想回滚要做出配置);
spring的声明式事务是基于aop的
spring aop 异常捕获原理:被拦截的方法需显式抛出异常,并不能经任何处理(如果自己捕获就不能被声明式事务感知),这样aop代理才能捕获到方法的异常,才能进行回滚,默认情况下aop只捕获runtimeexception的异常,但可以通过 。
配置来捕获特定的异常并回滚
换句话说在service的方法中不使用try catch 或者在catch中最后加上throw new runtimeexcetpion(),这样程序异常时才能被aop捕获进而回滚
解决方案:
方案1.方法中不做异常捕获,或者在catch语句中最后增加throw new runtimeexception()语句,以便让aop捕获异常再去回滚,并且在上层(webservice客户端,view层action)要继续捕获这个异常并处理
方案2.在方法的catch语句中增加:transactionaspectsupport.currenttransactionstatus().setrollbackonly();语句,手动回滚,这样上层就无需去处理异常
第二、在catch中异常抛出exception,并不是runtimeexception,导致也没有回滚
解决方法:
① 抛出exception,同时在事务声明中加上@transactional(rollbackfor = exception.class)
② 在catch添加语句
catch (exception e) { e.printstacktrace(); transactionaspectsupport.currenttransactionstatus().setrollbackonly();//就是这一句了,加上之后如果异常后会回滚的 }