return !(winner instanceof NoRollbackRuleAttribute);
于是,就成功走到了 else 分支里面,出了异常也 commit 了,你说神奇不神奇:
写到这里的时候,我突然想到了一个骚操作,甚至有可能变成一道沙雕面试题:
这个操作骚不骚,到底会回滚呢还是不回滚呢?
如果你在项目里看到这样的代码肯定是要骂一句傻逼的。
但是面试官就喜欢搞这些阴间的题目。
我想到这个问题的时候,我也不知道答案是什么,但是我知道答案还是在源码里面:
首先,从结果上可以直观的看到,经过 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)
别问,问就是因为代码是这样写的。
为什么代码要这样写呢?
我想可能设计这块代码的开发人员觉得 rollbackFor 的优先级比 noRollbackFor 高吧。
再来一个问题:
Spring 源码怎么匹配当前这个异常是需要回滚的?
别想那么复杂,大道至简,直接递归,然后一层层的找父类,对比名称就完事了。
你注意截图里面的注释:
一个是 Found it!
表示找到了,匹配上了,用了感叹号表示很开心。
一个是 If we've gone as far as we can go and haven't found it...
啥意思呢,这个 as far as 在英语里面是一个连词,表示“直到..为止..”的意思。引导的是状语从句,强调的是程度或范围。
所以,上面这句话的意思就是:
如果我们已经走到我们能走的最远的地方,还没匹配上,代码就只能这样写了:
异常类,最远的地方就是 Throwable.class。没匹配上,就返回 -1。
好了,通过两个没啥卵用的知识点,顺带学了点实战英语,关于业务代码出了异常回滚还是提交这一块的代码就差不多了。
但是我还是建议大家亲自去 Debug 一下,可太有意思了。
然后我们接着聊正常场景下的提交。
这个代码块里面,try 我们也聊了,catch 我们也聊了。
就差个 finally 了。
我看网上有的文章说 finally 里面就是 commit 的地方。
错了啊,老弟。
这里只是把数据库连接给重置一下。
方法上已经给你说的很清楚了:
Spring 的事务是基于 ThreadLocal 来做的。在当前的这个事务里面,可能有一些隔离级别、回滚类型、超时时间等等的个性化配置。
不管是这个事务正常返回还是出现异常,只要它完事了,就得给把这些个性化的配置全部恢复到默认配置。
所以,放到了 finally 代码块里面去执行了。
真正的 commit 的地方是这行代码:
那么问题又来了:
走到这里来了,事务一定会提交吗?
话可别说的那么绝对,兄弟,看代码: