摘要:嗨大家好呀,我是小米,一个31岁的Java开发工程师,今天依然在南京热辣滚烫的代码世界中努力生存,最近在准备一次社招面试,面到一题经典的不能再经典的老朋友:
嗨大家好呀,我是小米,一个31岁的Java开发工程师,今天依然在南京热辣滚烫的代码世界中努力生存,最近在准备一次社招面试,面到一题经典的不能再经典的老朋友:
“你说一下Spring的事务传播行为?”
我当场一愣:这不是我平时用得很顺手的@Transactional吗?怎么突然要我掏出原理了!
但你知道的,程序员嘛,手一抖就想深挖——于是乎,小米又熬了一晚,看完官方文档、源码、博客、项目代码……干脆整理出来这篇文章,咱不但要能回答,还得能讲出花儿来!
首先,要明确一件事:
这个问题不是在问你“记住了几个枚举常量”,而是在问你:
你知道这些传播行为怎么运作吗?
在实际项目中你用过哪些,遇到过什么坑,怎么解决的?
好啦,先正经解释一下:
在Spring中,事务传播行为(Propagation)定义了一个有事务的方法调用另一个有事务的方法时,应该如何处理事务上下文。
也就是说:
假如你现在在方法A里用了@Transactional,然后它调用了方法B,方法B也用了@Transactional,那——请问B要用A的事务吗?还是重新开一个新的?
这就是传播行为来决定的。
我们一个个来过——不靠死记硬背,而是讲“情景故事”,让你面试、写代码、debug都能瞬间反应。
1. PROPAGATION_REQUIRED(需要当前事务)
解释:
如果当前存在事务,就加入该事务;如果没有事务,就新建一个事务。
小米的故事:
就像你在吃火锅,突然你朋友来了。他说:“你已经点单了,那我就坐你这桌,咱们一起吃。”——省事儿省钱。
应用场景:
这是默认值,也是最常用的。一个方法调用另一个方法,大家共享一个事务,这样在操作数据库时统一提交或回滚。坑点提示:
事务失效的大部分锅就出在这里!例如:
结论:自调用会绕过代理,事务不会生效。
2. PROPAGATION_REQUIRES_NEW(新建一个事务)
解释:
总是新建一个事务。如果外面已经有事务了,就挂起外部事务。
小米的故事:
你跟朋友吃火锅,他还在点菜,这时候你说“我还有点事,我自己开张新桌先吃了!”等他点完再来找你。
应用场景:
A方法要执行B,但B无论成功失败都不能影响A。日志保存场景(即便主事务失败,日志也要记住)。示例代码:
3. PROPAGATION_NESTED(嵌套事务)
解释:
如果当前有事务,就在这个事务中创建一个“嵌套点”(savepoint);否则新建事务。
小米的故事:
你跟朋友合开一桌火锅,但你怕他点太多,于是你记录了自己点的那些菜。如果等会你觉得吃太撑了,可以退掉你点的,朋友的保留。
应用场景:
适合部分回滚的业务。注意:
需要数据库支持“保存点机制”(如MySQL的InnoDB)。不同于REQUIRES_NEW,它不挂起外部事务,而是在当前事务中设置回滚点。4. PROPAGATION_SUPPORTS(支持当前事务)
解释:
有事务就用,没有就非事务地运行。
小米的故事:
朋友在吃火锅你加入,你就跟着吃;朋友不吃,你也不点菜,喝点水看看剧。
应用场景:
读操作为主,灵活点即可。5. PROPAGATION_NOT_SUPPORTED(不支持事务)
解释:
当前有事务就挂起它,自己无事务地运行。
小米的故事:
“火锅我不吃了,我减肥呢。我在旁边点个水果拼盘,不跟你们掺和。”
应用场景:
一些不需要事务的代码,比如操作Redis、记录日志、调用远程服务等。6. PROPAGATION_NEVER(绝对不能有事务)
解释:
如果当前有事务,直接抛异常。
小米的故事:
“你这桌有火锅?那我不去了,油烟太重我过敏!”
应用场景:
真的极少用,除非你确定某段逻辑不能被事务管理(比如某些审计操作)。7. PROPAGATION_MANDATORY(必须要有事务)
解释:
如果当前没有事务,就抛异常。
小米的故事:
“火锅必须组团才能吃,我一个人不点。”
应用场景:
比如你设计了一段核心业务,必须放在事务中执行,不然就炸!背景:某服务A里调用B和C两个方法,都带有@Transactional,希望C失败了也不要影响A。
我脑子一拍,用了REQUIRES_NEW,C确实不影响A了。但新问题出现了:
B的方法是REQUIRED,它执行失败抛异常后,A事务回滚了,但C提交了!
等于C的数据和其他都不一致了!!
解决方案:
我加了异常处理和业务补偿,让C的事务与A“解耦”,但在逻辑层上又用“事件通知”方式做回滚补偿。
这个事让我意识到一个关键点:
传播行为不是事务边界的终点,而是事务策略的一部分。真正安全的业务逻辑,必须结合异常处理、日志、幂等、补偿等机制。
最后,送大家一段小米总结口诀:
必须有就MANDATORY,有也不行是NEVER;不管有没有就SUPPORTS,没有别跑是REQUIRED;挂起重开REQUIRES_NEW,嵌套事务NESTED修;不管事务我不管,NOT_SUPPORTED有你秀。这年头,光能写CRUD已经不够了,理解事务传播这种“细节上的大问题”,才是真正的Java高手之路。
如果你觉得这篇文章有帮助,欢迎【点赞+转发+在看】,也欢迎留言聊聊你在用事务传播时遇到的坑!
来源:雅雯教育分享