官方推荐的@Transactional事务,我还是不建议使用( 二 )


但是如果是编程式事务的话 , 业务代码中就会清清楚楚看到什么地方开启事务 , 什么地方提交 , 什么时候回滚 。 这样有人改这段代码的时候 , 就会强制他考虑要加的代码是否应该方法事务内 。
有些人可能会说 , 已经有了声明式事务 , 但是写代码的人没注意 , 这能怪谁 。
话虽然是这么说 , 但是我们还是希望可以通过一些机制或者规范 , 降低这些问题发生的概率 。
比如建议大家使用编程式事务 , 而不是声明式事务 。 因为 , 作者工作这么多年来 , 发生过不止一次开发者没注意到声明式事务而导致的故障 。
因为有些时候 , 声明式事务确实不够明显 。
声明式事务用不对容易失效除了事务的粒度问题 , 还有一个问题那就是声明式事务虽然看上去帮我们简化了很多代码 , 但是一旦没用对 , 也很容易导致事务失效 。
如以下几种场景就可能导致声明式事务失效:
1、@Transactional 应用在非 public 修饰的方法上
2、@Transactional 注解属性 propagation 设置错误
3、@Transactional 注解属性 rollbackFor 设置错误
4、同一个类中方法调用 , 导致@Transactional失效
5、异常被catch捕获导致@Transactional失效
6、数据库引擎不支持事务
以上几个问题 , 如果使用编程式事务的话 , 很多都是可以避免的 。
使用声明事务失效的问题我们发生过很多次 。 不知道大家有没有遇到过 , 我是实际遇到过的
因为Spring的事务是基于AOP实现的 , 但是在代码中 , 有时候我们会有很多切面 , 不同的切面可能会来处理不同的事情 , 多个切面之间可能会有相互影响 。
在之前的一个项目中 , 我就发现我们的Service层的事务全都失效了 , 一个SQL执行失败后并没有回滚 , 排查下来才发现 , 是因为一位同事新增了一个切面 , 这个切面里面做个异常的统一捕获 , 导致事务的切面没有捕获到异常 , 导致事务无法回滚 。
这样的问题 , 发生过不止一次 , 而且不容易被发现 。
很多人还是会说 , 说到底还是自己能力不行 , 对事务理解不透彻 , 用错了能怪谁 。
但是我还是那句话 , 我们确实无法保证所有人的能力都很高 , 也无法要求所有开发者都能不出错 。 我们能做的就是 , 尽量可以通过机制或者规范 , 来避免或者降低这些问题发生的概率 。
其实 , 如果大家有认真看过阿里巴巴出的那份Java开发手册的话 , 其实就能发现 , 其中的很多规约并不是完完全全容易被人理解 , 有些也比较生硬 , 但是其实 , 这些规范都是从无数个坑里爬出来的开发者们总结出来的 。
关于@Transactional的用法 , 规约中也有提到过 , 只不过规约中的观点没有我这么鲜明:
官方推荐的@Transactional事务,我还是不建议使用文章插图
总结最后 , 相信本文的观点很多人都并不一定认同 , 很多人会说:Spring官方都推荐无侵入性的声明式事务 , 你有啥资格出来BB。
说实话 , 刚工作的前几年 , 我也热衷于使用声明式事务 , 觉得很干净 , 也很"优雅" 。 觉得师兄们使用编程式事务多此一举 , 没有工匠精神 。
但是慢慢的 , 线上发生过几次问题之后 , 我们复盘后发现 , 很多时候你自己写的代码很优雅 , 这完全没问题 。
但是 , 优雅的同时也带来了一些副作用 , 师兄们又不能批评我 , 因为我的用法确实没错…
所以 , 有些事 , 还是要痛过之后才知道 。
【官方推荐的@Transactional事务,我还是不建议使用】当然 , 本文并不要求大家一定要彻底不使用声明式事务 , 只是建议大家日后在使用事务的时候 , 能够考虑到本文中提到的观点 , 然后自行选择 。


推荐阅读