美文网首页
一个关于Spring事务的坑(Transaction rolle

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

作者: Guncorpse | 来源:发表于2019-01-18 17:06 被阅读0次

    在使用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了!

    相关文章

      网友评论

          本文标题:一个关于Spring事务的坑(Transaction rolle

          本文链接:https://www.haomeiwen.com/subject/phondqtx.html