当Transactional碰到锁,有个大坑,要小心。 (5)

org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

当Transactional碰到锁,有个大坑,要小心。

前面我们聊事务开启的时候,说的是第 382 行代码。

然后 try 代码块里面执行的是我们的业务代码。

现在,我们要研究事务的提交了,所以主要看我框起来的地方。

首先 catch 代码块里面,392 行,看方法名称已经非常的见名知意了:

completeTransactionAfterThrowing 在抛出异常之后完成事务的提交。

你看我的代码,只是用到了 @Transactional 注解,并没有指定异常。

那么问题就来了:

Spring 管理的事务,默认回滚的异常是什么呢?

如果你不知道答案,就可以带着问题去看源码。

如果你知道答案,但是没有亲眼看到对应的代码,那么也可以去寻找源码。

如果你知道答案,也看过这部分源码,温故而知新。

先说答案:默认回滚的异常是 RuntimeException 或者 Error

我只需要在业务代码里面抛出一个 RuntimeException 的子类,比如这样的:

当Transactional碰到锁,有个大坑,要小心。

然后在 392 行打上断点,开始调试就完事了:

当Transactional碰到锁,有个大坑,要小心。

只需要往下调试几步,你就能走到这个方法来:

org.springframework.transaction.interceptor.RuleBasedTransactionAttribute#rollbackOn

当Transactional碰到锁,有个大坑,要小心。

发现这个 winner 对象为空,接着走了这个逻辑:

return super.rollbackOn(ex);

答案就藏着这行代码的背后:

当Transactional碰到锁,有个大坑,要小心。

如果异常类型是 RuntimeException 或者 Error 的子类,那么就返回 true,即需要回滚,调用 rollback 方法:

当Transactional碰到锁,有个大坑,要小心。

如果返回为 false,则表示不需要回滚,调用 commit 方法:

当Transactional碰到锁,有个大坑,要小心。

那么怎么让它返回 false 呢?

很简单嘛,这样一搞就好了:

当Transactional碰到锁,有个大坑,要小心。

框架给你留了口子,你就把它用起来。

当我把代码改成上面那样,然后重新启动项目,再次访问代码。

我们去寻找出现指定异常不回滚的具体的实现逻辑在哪。

其实也在我们刚刚看到的方法里面:

当Transactional碰到锁,有个大坑,要小心。

你看,这个时候 winner 不为 null 了。它是一个 NoRollbackRuleAttribute 对象了。

所以就走入这行代码,返回 false 了:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzdfsx.html