spring事务传播机制
spring事务传播机制
Spring 的事务传播机制指的是在多个事务方法相互调用时,事务应该如何传播的规则。它定义了被调用方法是在调用方的事务中运行,还是自己开启新事务,或者完全不参与事务等行为。这是 Spring 声明式事务管理的核心特性之一,通过 @Transactional(propagation = Propagation.XXX) 注解来指定。
Spring 定义了 7 种不同的事务传播行为,对应于 Propagation 枚举:
1.Propagation.REQUIRED (默认值):
- 含义:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。
- 场景:这是最常用的传播行为,适用于绝大多数情况。它确保多个方法调用(无论嵌套与否)都在同一个事务上下文中执行,保证原子性。
- 示例:方法 A(有事务)调用方法 B(REQUIRED),B 加入 A 的事务;方法 A(无事务)调用方法 B(REQUIRED),B 新建一个事务。
2.Propagation.SUPPORTS: - 含义:如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。
- 场景:适用于方法既可以工作在事务环境中,也可以安全地工作在非事务环境中(通常是查询操作)。方法的执行不强制要求有事务。
- 示例:方法 A(有事务)调用方法 B(SUPPORTS),B 加入 A 的事务;方法 A(无事务)调用方法 B(SUPPORTS),B 以非事务方式执行(无回滚)。
3.Propagation.MANDATORY: - 含义:强制要求当前必须存在事务。如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
- 场景:用于严格要求方法必须在事务上下文中被调用的情况,通常在需要保证操作原子性且不能独立运行时使用。
- 示例:方法 A(有事务)调用方法 B(MANDATORY),B 加入 A 的事务;方法 A(无事务)调用方法 B(MANDATORY),抛出 IllegalTransactionStateException。
4.Propagation.REQUIRES_NEW: - 含义:总是创建一个新的事务。如果当前存在事务,则将当前事务挂起(暂停),创建一个新的事务执行。
- 场景:被调用的方法需要在一个独立于调用方事务的新事务中运行,无论调用方是否已有事务。被调用方法的提交或回滚不影响调用方的事务(反之亦然)。常用于需要记录操作日志(即使主业务失败也要记录)、或调用外部服务等需要独立提交的场景。
- 示例:方法 A(有事务)调用方法 B(REQUIRES_NEW),A 的事务被挂起,B 开启一个新事务独立执行。B 提交或回滚后,A 的事务恢复执行。两者独立。
5.Propagation.NOT_SUPPORTED: - 含义:以非事务方式执行操作。如果当前存在事务,则将该事务挂起。
- 场景:方法不需要事务支持,且明确要求避免在事务内执行(例如执行一些特殊的与事务性资源管理器不兼容的操作)。
- 示例:方法 A(有事务)调用方法 B(NOT_SUPPORTED),A 的事务被挂起,B 以非事务方式执行。B 执行完后,A 的事务恢复。B 的执行完全没有事务保障。
6.Propagation.NEVER: - 含义:以非事务方式执行。如果当前存在事务,则抛出异常。
- 场景:严格要求该方法不能在事务上下文中被调用。
- 示例:方法 A(有事务)调用方法 B(NEVER),抛出 IllegalTransactionStateException;方法 A(无事务)调用方法 B(NEVER),B 以非事务方式执行。
7.Propagation.NESTED: - 含义:如果当前存在事务,则在当前事务内创建一个嵌套事务。如果当前没有事务,则其行为与 REQUIRED 相同(创建一个新事务)。
- 场景:嵌套事务是外部事务的子部分。嵌套事务可以独立于外部事务进行提交或回滚(使用保存点savepoint实现)。如果外部事务回滚,嵌套事务也会回滚;嵌套事务回滚不会导致外部事务回滚(除非外部事务捕获异常并选择回滚)。适用于希望部分操作回滚但不影响整体事务的场景(例如批量处理中处理单个记录失败)。
- 示例:方法 A(有事务)调用方法 B(NESTED),B 在 A 的事务内创建一个嵌套事务。B 可以回滚而不影响 A 的事务点(保存点之前的操作);但如果 A 的事务最终回滚,则 B 所做的所有操作也会回滚。
核心区别点总结: - 加入 vs 新建事务:REQUIRED, SUPPORTS, MANDATORY 是“加入派”(有则加入),REQUIRES_NEW 是“独立派”(一定新建)。
- 事务依赖:REQUIRES_NEW 创建的事务与调用方事务完全独立。NESTED 是调用方事务的子事务(依赖并受其约束)。
- 回滚影响:
- REQUIRED/MANDATORY/SUPPORTS(在事务内时):方法回滚会导致整个事务(包含所有嵌套操作)回滚。
- REQUIRES_NEW:自身回滚不影响调用方事务;调用方事务回滚不影响它(除非它在执行中被挂起后外部事务回滚了它的结果所在的数据范围,这很复杂且依赖具体数据库/实现,一般不依赖)。
- NESTED:自身回滚可控制在小范围(回滚到保存点);调用方事务回滚会连带回滚它。
- 非事务执行:SUPPORTS, NOT_SUPPORTED, NEVER 都可能以非事务执行,但条件不同(有无事务、是否允许有事务)。
如何选择合适的传播行为? - REQUIRED (使用最多):适用于绝大多数业务方法调用链,保证整个操作在一个事务内。
- REQUIRES_NEW:需要与被调用方法完全解耦事务(如记录日志、调用独立服务)、或者希望被调用方法独立提交避免阻塞主事务时使用。
- NESTED:适用于希望在主事务中执行可能失败但可恢复的子任务(如批处理)。注意:NESTED 需要底层的 JDBC 驱动和数据库支持保存点。
- SUPPORTS:主要用于只读查询操作,可在有无事务环境中安全运行。
- MANDATORY/NEVER/NOT_SUPPORTED:特定场景的约束要求,使用较少。
理解事务传播行为是设计和实现可靠、一致的事务性服务的关键。选择哪种行为取决于你的具体业务逻辑和对事务边界的需求。始终清楚每个方法在事务上下文中的行为以及它们之间的相互影响。