事务隔离级别和传播机制是独立配置项:隔离级别解决并发事务数据可见性问题,传播机制决定方法调用链中事务的延续或新建逻辑,二者可组合使用但选型逻辑各自独立。

Java 事务隔离级别和传播机制不是“配对使用”的关系,而是解决两类不同问题的独立配置项:隔离级别管的是多个并发事务之间数据可见性怎么控制,传播机制管的是方法调用链里事务该怎么延续或新建。它们可以组合设置,但选型逻辑各自独立。
隔离级别怎么选:看数据一致性要求和并发压力
Spring 的 isolation 参数默认为 Isolation.DEFAULT,即使用底层数据库的默认级别(MySQL 是 REPEATABLE READ,Oracle 是 READ COMMITTED)。除非业务有明确需求,否则不建议随意更改。
- READ_COMMITTED:适合大多数 Web 应用。能防止脏读,允许不可重复读和幻读,性能较好,且语义清晰——“只读已提交的数据”。比如用户余额查询、订单状态展示。
- REPEATABLE_READ:MySQL 默认,适合需要同一事务内多次查询结果一致的场景,比如生成报表前校验库存、分步扣减时避免中间态干扰。注意:MySQL 通过 MVCC + Next-Key Lock 解决了幻读,但逻辑上仍属该级别。
- SERIALIZABLE:极少用。强制串行执行,性能损耗大,仅用于极敏感场景(如金融核心账务轧差),通常用应用层加锁或业务规则替代。
- READ_UNCOMMITTED:基本不用。可能读到未提交数据,风险高,仅调试或特殊统计类场景可临时启用。
传播机制怎么选:看方法在调用链中的角色
传播行为决定当前方法是否参与事务、是否新建事务、是否挂起现有事务。最常用的是 REQUIRED(默认),其余按需选用:
- REQUIRED:核心业务方法(如下单、支付)都用它。保证整个业务链在一个事务里,要么全成要么全退。
- REQUIRES_NEW:日志记录、审计、通知类操作。即使外层事务回滚,这些操作也要落库,比如写入操作日志、发 MQ 消息(配合可靠投递)。
-
NESTED:支持保存点的场景,比如批量导入中某条失败,只回滚当前条而不影响前面成功的。注意:HikariCP + MySQL 需开启
allowMultiQueries=true,且 Spring 默认使用 JDBC 保存点,非所有数据库都完全支持。 - NOT_SUPPORTED:纯查询或缓存刷新类操作。明确不需要事务,还能减少连接占用,比如首页广告位预热、定时任务中的统计汇总。
- MANDATORY / NEVER:多用于框架层或强约束接口,普通业务代码很少主动设,主要用于防御性检查(如确保某个工具方法一定在事务外运行)。
组合使用的典型例子
实际写法是把两个参数一起加在 @Transactional 上,互不影响:
-
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)—— 标准下单服务,要求读已提交数据,且必须纳入外层事务。 -
@Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRES_NEW)—— 财务对账任务,需数据快照一致,且必须独立提交,不受调用方事务影响。 -
@Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)—— 缓存预热查询,不走事务、只读、避免持有连接。
容易踩的坑
这两个配置生效的前提是:方法必须是 public,必须被 Spring 容器管理(@Service/@Component),且调用必须走代理(不能本类 self-invocation)。另外:
- 隔离级别修改后,要确认数据库实际支持——比如 H2 内存库不支持 SERIALIZABLE;
- REQUIRES_NEW 会新建物理连接(取决于数据源配置),高频使用可能触发连接池耗尽;
- NESTED 在 PostgreSQL 和 Oracle 中行为与 MySQL 不同,上线前务必验证;
- 不要为了“看起来严谨”而盲目提高隔离级别或传播复杂度,多数问题靠合理拆分业务、幂等设计、最终一致性更稳妥。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











