一个关于Spring事务的坑(Transaction rolle

2019-01-18  本文已影响0人  Guncorpse

在使用Jpa的@Version的时候偶然发现了一个Spring事务的坑,花了一个下午的时间才成功解决,记录一下。

@Version当修改或删除操作的数据版本不一致的时候会抛出一个异常:
ObjectOptimisticLockingFailureException

Service用以下代码捕获了这个异常,消化并抛出了一个新的自定义异常:

        try {
          //调用持久化方法抛出ObjectOptimisticLockingFailureException异常
        } catch (ObjectOptimisticLockingFailureException e) {
            if (logger.isErrorEnabled()) {
                logger.error(e.getMessage());
            }
            //捕获处理后抛出一个新的自定义异常
            throw new SkeletonBaseException("数据版本错误");
        } catch (Exception e) {
            if (logger.isErrorEnabled()) {
                logger.error(e.getMessage());
            }
            throw SkeletonBaseException.getException(e, e.getMessage());
        }

但是在Controller的最终异常处理中

        try {
            //调用上面的方法
        } catch (Exception e) {
            e.printStackTrace();
            if (logger.isErrorEnabled()) {
                logger.error(e.getMessage());
            }
            responseRange.setException(e);
        }
        return responseRange;

却得到了一个完全不一样的异常信息:
Transaction rolled back because it has been marked as rollback-only
这个异常信息是说事务已经回滚,因为它被标记成了回滚。

这里就很奇怪了。
按照我的想法,这个异常信息应该是Service抛出的自定义异常数据版本错误才对啊。
想了一下这就说明在Service返回Controller的过程中还发生了一个新的异常,而把我的异常顶掉了。
为什么会发生这种事情?
在网上查了许多大神的资料,Debugger了半天Spring的源码。
最终总结出了一个答案
Spring的事务切面认为Service的方法没有抛出异常,在Service结束后,打算正常Commit提交事务!但是这个事务已经被标记成了rollback-only状态,所以提交失败,抛出上面出乎意料的异常信息!
异常被顶掉的原因知道了。
但是我们Service明明最终抛出了一个自定义异常啊!它跑到哪里去了!
为什么事务切面认为没有抛出异常呢?!
这就是坑之所在了!
我的自定义异常继承了Exception而不是RuntimeException
因为知道Spring的事务默认回滚是发生RuntimeException所以特地配置了rollbackFor = Exception.class
按理来说不应该Commit而是正常rollback。
不过问题范围缩小了,又针对性的搜索了好一阵儿。
原因:
try{}catch(){}这样的代码块中,最后必须抛出一个RuntimeException,Spring事务切面才会认为你的方法有异常出现!即使配置了rollbackFor = Exception.class也不管用!
解决方法:把自定义异常改成继承RuntimeException就OK了!

上一篇下一篇

猜你喜欢

热点阅读