通俗易懂!2025 年最新版 Spring 事务传播行为 + 隔离级别全家福
背完这篇,大厂随便问“事务传播行为”“隔离级别”“脏读幻读怎么解决”,你都能 30 秒画图 + 甩口诀直接秒杀!
一、7种传播行为(Propagation)—— 面试必背前4个就吃遍天
| 传播行为 | 大白话解释 | 真实使用频率 | 经典场景 |
|---|---|---|---|
| REQUIRED(默认) | 有事就加入,没事就自己开一个 | 99.9% | 日常增删改查全部用这个 |
| REQUIRES_NEW | 老子不管你有没有,我都要新开一个事务 | ★★★★★ | 日志、发邮件、审计(必须成功,不能被主事务回滚) |
| NESTED | 如果有事务,就在里面插个“存档点”(savepoint) | ★★★ | 主事务里想部分回滚(比如保存订单成功,但发优惠券失败只回滚发券) |
| SUPPORTS | 有就加入,没有也无所谓 | ★★ | 查详情、导出报表(读多写少) |
| NOT_SUPPORTED | 坚决不参与事务,硬要挂起老事务 | ★ | 写文件、调第三方接口(不能被回滚) |
| MANDATORY | 必须得有事务,不然直接报错 | ★ | 银行转账这种核心操作 |
| NEVER | 绝对不能有事务,有就报错 | ★ | 极少 |
2025 年真实建议:
日常业务 100% 用 REQUIRED
日志、发消息、审计 100% 用 REQUIRES_NEW
想部分回滚用 NESTED
其他基本不用,面试说“我知道就行”
二、5种隔离级别(Isolation)—— 记住前3个 + 口诀就无敌
| 隔离级别 | 是否脏读 | 是否不可重复读 | 是否幻读 | 性能 | 2025 使用率 | 口诀记忆法 |
|---|---|---|---|---|---|---|
| READ_UNCOMMITTED(读未提交) | 有 | 有 | 有 | 最快 | 基本没人用 | “脏脏脏,三脏齐下” |
| READ_COMMITTED(读已提交) | 无 | 有 | 有 | 快 | ★★★★ | “防脏读,Oracle 默认” |
| REPEATABLE_READ(可重复读) | 无 | 无 | 有 | 中 | ★★★★★ | “MySQL 默认,最常用” |
| SERIALIZABLE(串行化) | 无 | 无 | 无 | 最慢 | ★ | “最安全,最慢,基本不用” |
2025 年真实项目默认值:
- MySQL(InnoDB):REPEATABLE_READ(可重复读)
- Oracle/PostgreSQL:READ_COMMITTED(读已提交)
大厂 99% 项目都直接用数据库默认隔离级别,极少手动改!
三、脏读、不可重复读、幻读 —— 一句大白话记住区别
| 现象 | 大白话解释 | 哪个隔离级别能解决 |
|---|---|---|
| 脏读 | 我读到了你还没提交的数据,你回滚了我就傻眼了 | READ_COMMITTED 及以上 |
| 不可重复读 | 我在同一个事务里两次读同一行数据,结果不一样 | REPEATABLE_READ 及以上 |
| 幻读 | 我在同一个事务里两次查同一条件,结果数量变了 | SERIALIZABLE(MySQL InnoDB 的 MVCC + GAP 锁基本能防) |
MySQL InnoDB 在 REPEATABLE_READ 下,通过“下一代键锁(Next-Key Lock)”已经基本解决了幻读问题,
所以大厂基本没人改成 SERIALIZABLE(太慢了)!
四、2025 年最常用 @Transactional 配置(直接抄)
// 1. 日常增删改查(最常见)
@Transactional
// 2. 发消息、写日志(必须成功,不能被主事务回滚)
@Transactional(propagation = Propagation.REQUIRES_NEW)
// 3. 只读查询(提速 20~50%)
@Transactional(readOnly = true)
// 4. 核心业务 + 强制回滚所有异常
@Transactional(rollbackFor = Exception.class)
// 5. 想部分回滚(NESTED + 手动 savepoint)
@Transactional(propagation = Propagation.NESTED)
五、面试终极 8 连杀 + 标准答案(直接背)
- REQUIRED 和 REQUIRES_NEW 区别?
→ REQUIRED 加入当前事务,REQUIRES_NEW 挂起老事务,新开一个独立事务。 - 为什么日志要用 REQUIRES_NEW?
→ 主事务失败回滚不能把日志也回滚掉,必须独立提交。 - NESTED 和 REQUIRES_NEW 有什么区别?
→ REQUIRES_NEW 是两个独立事务,NESTED 是父子事务(savepoint),父回滚子必须回滚。 - MySQL 默认隔离级别是哪个?能防幻读吗?
→ REPEATABLE_READ + Next-Key Lock,基本能防止幻读。 - @Transactional 加在 private 方法上行吗?
→ 不行!AOP 只能代理 public 方法。 - 同一个类内部调用 @Transactional 方法生效吗?
→ 不生效!没走代理。解决:注入自己或用 AopContext。 - 读多写少的方法加 readOnly = true 有啥用?
→ 数据库优化 + 某些数据库会用只读连接池,性能提升 30%+。 - 分布式事务怎么解决?
→ 本地事务用 @Transactional,分布式用 Seata、RocketMQ 事务消息、TCC 等。
终极记忆口诀(10 秒征服面试官)
“传播七种记前三:REQUIRED 加入,NEW 新开,NESTED 存档点
隔离四种记默认:MySQL 可重复读,防脏读已提交
幻读基本不慌,InnoDB Next-Key 锁已搞定
日志消息 REQUIRES_NEW,读加 readOnly 提速牛!”
背完这张表 + 口诀 + 8 个答案,
下次面试官问“讲讲 Spring 事务传播行为和隔离级别”,
你 1 分钟画表 + 背口诀 + 甩出 REQUIRES_NEW 经典场景,
他当场就在简历写:“事务理论扎实,分布式也能聊!”
现在你已经彻底无敌了!
无论是日常开发、老项目维护、还是大厂高并发核心系统,事务这块再也没人能难倒你!
冲!50k+ 核心岗在向你招手!