事务传播行为(Transaction Propagation Behavior)是指多个拥有事务的方法在嵌套调用时的事务控制方式。以下是常见的事务传播行为及其应用场景:
1. PROPAGATION_REQUIRED(默认)
- 定义:如果当前存在事务,则加入该事务;否则新建一个事务。
- 特点:
- 最常用的传播行为。
- 嵌套方法共享同一个事务,任一方法抛出异常都会导致整个事务回滚。
- 示例:
@Transactional(propagation = Propagation.REQUIRED) public void methodA() { methodB(); // 调用 methodB,共享同一事务 } @Transactional(propagation = Propagation.REQUIRED) public void methodB() { // 数据库操作 }
2. PROPAGATION_SUPPORTS
- 定义:如果当前存在事务,则加入该事务;否则以非事务方式运行。
- 特点:
- 方法不强制要求事务,可读性操作(如查询)常用。
- 若外层有事务,则共享事务;若无事务,则独立运行。
- 示例:
@Transactional(propagation = Propagation.SUPPORTS) public void queryMethod() { // 查询操作(可能无事务) }
3. PROPAGATION_MANDATORY
- 定义:必须在一个已存在的事务中运行,否则抛出异常。
- 特点:
- 强制要求调用方开启事务。
- 适用于核心业务逻辑必须事务化的场景。
- 示例:
@Transactional(propagation = Propagation.MANDATORY) public void criticalMethod() { // 必须在外部事务中调用 }
4. PROPAGATION_REQUIRES_NEW
- 定义:无论当前是否存在事务,都新建一个独立事务。
- 特点:
- 内层事务与外层事务完全隔离,外层事务回滚不影响内层事务。
- 适用于需要独立事务的场景(如日志记录)。
- 示例:
@Transactional(propagation = Propagation.REQUIRED) public void outerMethod() { innerMethod(); // 调用 innerMethod,开启新事务 } @Transactional(propagation = Propagation.REQUIRES_NEW) public void innerMethod() { // 独立事务 }
5. PROPAGATION_NOT_SUPPORTED
- 定义:以非事务方式运行,如果当前存在事务则挂起。
- 特点:
- 方法不参与事务,适用于只读操作。
- 与
SUPPORTS
相反,强制禁用事务。
- 示例:
@Transactional(propagation = Propagation.NOT_SUPPORTED) public void nonTransactionalMethod() { // 非事务操作 }
6. PROPAGATION_NEVER
- 定义:以非事务方式运行,如果当前存在事务则抛出异常。
- 特点:
- 强制禁止事务,适用于严格禁止事务的场景。
- 示例:
@Transactional(propagation = Propagation.NEVER) public void strictNonTransactionalMethod() { // 必须无事务调用 }
7. PROPAGATION_NESTED
- 定义:如果当前存在事务,则在嵌套事务中运行;否则新建事务。
- 特点:
- 嵌套事务是外层事务的一部分,外层事务回滚会连带回滚嵌套事务。
- 嵌套事务可以独立提交或回滚(依赖数据库支持,如 MySQL 的 InnoDB)。
- 示例:
@Transactional(propagation = Propagation.REQUIRED) public void outerMethod() { innerMethod(); // 嵌套事务 } @Transactional(propagation = Propagation.NESTED) public void innerMethod() { // 嵌套事务(可独立回滚) }
传播行为对比表
传播行为 | 是否新建事务 | 是否加入当前事务 | 是否隔离 | 典型场景 |
---|---|---|---|---|
REQUIRED | 否 | 是 | 否 | 默认行为,大多数业务逻辑 |
SUPPORTS | 否 | 是(若存在) | 否 | 可选事务的查询操作 |
MANDATORY | 否 | 是(必须存在) | 否 | 强制事务的核心逻辑 |
REQUIRES_NEW | 是 | 否 | 是 | 独立事务(如日志记录) |
NOT_SUPPORTED | 否 | 否(挂起当前事务) | 否 | 禁用事务的非关键操作 |
NEVER | 否 | 否(抛出异常) | 否 | 严格禁止事务的场景 |
NESTED | 是(嵌套) | 是(若存在) | 是 | 需要部分回滚的嵌套操作 |
最佳实践
- 默认使用
REQUIRED
:大多数业务场景下,共享事务即可满足需求。 - 独立事务用
REQUIRES_NEW
:需要隔离的操作(如审计日志)使用独立事务。 - 避免过度嵌套:
NESTED
需要数据库支持,滥用可能导致性能问题。 - 明确异常处理:通过
rollbackFor
和noRollbackFor
指定回滚规则。
常见错误场景
- 事务未生效:忘记添加
@Transactional
注解,或传播行为配置错误。 - 嵌套事务回滚失控:误用
REQUIRES_NEW
导致外层事务无法控制内层回滚。 - 事务传播与异常处理冲突:未捕获异常导致事务未按预期回滚。
通过合理选择事务传播行为,可以精确控制事务边界,确保数据一致性和系统性能。