原文来自于:zha-ge.cn/java/110
你以为自动开启?Spring 事务支持其实还需要这几步!
有朋友问我:"咱们这个Spring的
@Transactional
不是加了就有用吗?明明写了注解,怎么数据还没回滚?"我一口老血险些喷出来。今天就聊一聊,这个看似贴心,实则有点坑的Spring事务自动支持,顺便聊点亲身"翻车"经历。
那一年,我天真地以为"它会为我全部安排"
初入Spring的时候,官网上的例子让我信誓旦旦。咱们的业务代码就一堆:
java
@Transactional
public void transferMoney(Account from, Account to, BigDecimal amount) {
from.withdraw(amount);
to.deposit(amount);
// 反正出错自动回滚吧
}
这,就是我的全部防线。
- 以为只要加上
@Transactional
,万事OK; - 以为异常一抛出,就会自动ROLL BACK;
- 以为......
- 以为的都很美好,现实嘛,只有坑。
踩坑瞬间
说出来你别笑,真的有被气哭的冲动。
-
自己调用自己没炸开花? 方法A调方法B,B上挂了
@Transactional
,结果B挂了,事务没回滚。为什么?Spring事务代理是基于AOP做的,自己call自己直接调用了原生方法,代理不参与,事务"不感知"。 -
异常类型也分三六九等? 非运行时异常(比如
Exception
)抛出,没有回滚? 不骗你,Spring默认只对RuntimeException
和Error
回滚,Catch到Exception
手动抛了也不一定行。脑海里才浮现项目经理的残忍微笑。 -
少了配置,一切白搭? 没开@EnableTransactionManagement,你的@Transactional注解跟写笑话差不多......
代码片段是这样"错过"的:
java
@Service
public class MoneyTransferService {
@Transactional
public void foo() { ... }
public void bar() {
this.foo(); // Spring无感知,直接裸奔
}
}
你说气人不气人?
解决姿势
后来,老伙计们交了我几招。
- 代理自己?用外部调用或者注入自身再调用。
applicationContext.getBean(MoneyTransferService.class).foo();
- 抛异常?别自己捕获闷头吃,有需要就throw new RuntimeException();
- 配置开关要开,否则全是"喷水池"。
- 在
@Configuration
类上加@EnableTransactionManagement
。
- 在
经验启示
踩了这么多坑,留点彩蛋给大家:
遇到的问题 | 解决建议 |
---|---|
方法内调用无效 | 用代理、注入自身bean调用 |
抛了Exception没回滚 | 只针对RuntimeException或自定义 |
配置项未启用 | 加@EnableTransactionManagement |
顺手贴个配置样板:
java
@Configuration
@EnableTransactionManagement
public class TxConfig {
// 数据源/事务管理器配置省略
}
收个小尾巴
回头看吵吵嚷嚷那几次,恨不得给每个加@Transactional
的老哥都发瓶红牛。 Spring事务能省心也能坑人,关键细节别假设"自动就给你安排清楚"。多踩几坑就记住了------写代码是自己的,掉进坑里只能自己爬,兄弟们共勉!
--- 以上,整个故事就这些。不聊了,我去修bug了 🤦♂️。