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

return !(winner instanceof NoRollbackRuleAttribute);

于是,就成功走到了 else 分支里面,出了异常也 commit 了,你说神奇不神奇:

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

写到这里的时候,我突然想到了一个骚操作,甚至有可能变成一道沙雕面试题:

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

这个操作骚不骚,到底会回滚呢还是不回滚呢?

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

如果你在项目里看到这样的代码肯定是要骂一句傻逼的。

但是面试官就喜欢搞这些阴间的题目。

我想到这个问题的时候,我也不知道答案是什么,但是我知道答案还是在源码里面:

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

首先,从结果上可以直观的看到,经过 for 循环之后, winner 是 RollbackRuleAttribute 对象,所以下面的代码返回 true,需要回滚:

return !(winner instanceof NoRollbackRuleAttribute);

问题就变成了 winner 为什么经过 for 循环之后是 RollbackRuleAttribute?

答案需要你自己去调试一下,很容易就明白了,我描述起来比较费劲。

简单一句话:导致 winner 是 RollbackRuleAttribute 的原因,就是因为被循环的这个 list 是先把 RollbackRuleAttribute 对象 add 了进去。

那么为什么 RollbackRuleAttribute 对象先加入到集合呢?

org.springframework.transaction.annotation.SpringTransactionAnnotationParser#parseTransactionAnnotation(org.springframework.core.annotation.AnnotationAttributes)

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

别问,问就是因为代码是这样写的。

为什么代码要这样写呢?

我想可能设计这块代码的开发人员觉得 rollbackFor 的优先级比 noRollbackFor 高吧。

再来一个问题:

Spring 源码怎么匹配当前这个异常是需要回滚的?

别想那么复杂,大道至简,直接递归,然后一层层的找父类,对比名称就完事了。

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

你注意截图里面的注释:

一个是 Found it!

表示找到了,匹配上了,用了感叹号表示很开心。

一个是 If we've gone as far as we can go and haven't found it...

啥意思呢,这个 as far as 在英语里面是一个连词,表示“直到..为止..”的意思。引导的是状语从句,强调的是程度或范围。

所以,上面这句话的意思就是:

如果我们已经走到我们能走的最远的地方,还没匹配上,代码就只能这样写了:

异常类,最远的地方就是 Throwable.class。没匹配上,就返回 -1。

好了,通过两个没啥卵用的知识点,顺带学了点实战英语,关于业务代码出了异常回滚还是提交这一块的代码就差不多了。

但是我还是建议大家亲自去 Debug 一下,可太有意思了。

然后我们接着聊正常场景下的提交。

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

这个代码块里面,try 我们也聊了,catch 我们也聊了。

就差个 finally 了。

我看网上有的文章说 finally 里面就是 commit 的地方。

错了啊,老弟。

这里只是把数据库连接给重置一下。

方法上已经给你说的很清楚了:

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

Spring 的事务是基于 ThreadLocal 来做的。在当前的这个事务里面,可能有一些隔离级别、回滚类型、超时时间等等的个性化配置。

不管是这个事务正常返回还是出现异常,只要它完事了,就得给把这些个性化的配置全部恢复到默认配置。

所以,放到了 finally 代码块里面去执行了。

真正的 commit 的地方是这行代码:

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

那么问题又来了:

走到这里来了,事务一定会提交吗?

话可别说的那么绝对,兄弟,看代码:

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

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