51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Spring 有哪几种事务传播行为?它们有什么区别?

你好,我是猿java

Spring 事务传播行为(Propagation Behavior)定义了一个事务方法被另一个事务方法调用时事务的边界和行为。这篇文章,我们将深度分析它们的原理以及对比它们之间的差异。

  1. 事务传播行为概述 {#1-事务传播行为概述} =========================

在 Spring 中,Propagation 枚举类型定义了七种主要的事务传播行为:

  1. REQUIRED
  2. REQUIRES_NEW
  3. SUPPORTS
  4. NOT_SUPPORTED
  5. MANDATORY
  6. NEVER
  7. NESTED

此外,NESTED 传播行为在某些数据源(如支持嵌套事务的数据库)下可用。

  1. 原理分析 {#2-原理分析} =================

事务传播行为主要决定了在一个事务方法被调用时,当前存在的事务(如果有)应该如何被处理。以下是其原理分析:

  • 事务的存在检查:当一个方法(被调用者)执行时,它会检查调用它的方法(调用者)是否存在活动事务。

  • 决定是否挂起、重用或创建新事务:根据传播行为的不同,调用者可能会被挂起,或者调用者的方法可能会加入到现有事务中,或者开启一个全新的事务。

  • 事务的边界控制:传播行为还控制了事务的提交和回滚边界,确保在复杂调用链中事务的一致性与完整性。

  1. 各种传播行为的示例分析 {#3-各种传播行为的示例分析} ===============================

3.1 REQUIRED {#3-1-REQUIRED}

定义:支持当前事务。如果没有事务,就新建一个事务。

原理:调用者存在事务,方法加入到这个事务中;否则,开启新事务。

示例

|------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 | @Transactional(propagation = Propagation.REQUIRED) public void methodA() { // 执行数据库操作 methodB(); } @Transactional(propagation = Propagation.REQUIRED) public void methodB() { // 执行数据库操作 } |

分析methodA 开启事务,methodB 加入到同一个事务中。如果 methodA 回滚,methodB 也会回滚。

3.2 REQUIRES_NEW {#3-2-REQUIRES-NEW}

定义:新建事务,如果存在事务,就将当前事务挂起。

原理:无论调用者是否存在事务,方法都会开启一个独立的新事务。

示例

|------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 | @Transactional(propagation = Propagation.REQUIRED) public void methodA() { // 执行数据库操作 methodB(); } @Transactional(propagation = Propagation.REQUIRES_NEW) public void methodB() { // 执行数据库操作 } |

分析methodAmethodB 各自有独立的事务。如果 methodB 回滚,不会影响 methodA 的事务。

3.3 SUPPORTS {#3-3-SUPPORTS}

定义:支持当前事务,如果存在事务,就加入;否则,以非事务方式执行。

原理:依赖调用者是否有事务,调用者有则参与事务,无则不使用事务。

示例

|------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 | @Transactional(propagation = Propagation.REQUIRED) public void methodA() { // 执行数据库操作 methodB(); } @Transactional(propagation = Propagation.SUPPORTS) public void methodB() { // 执行数据库操作 } |

分析 :如果 methodA 调用 methodBmethodB 会参与 methodA 的事务。如果 methodB 被独立调用,则以非事务方式执行。

3.4 NOT_SUPPORTED {#3-4-NOT-SUPPORTED}

定义:以非事务方式执行操作,如果存在事务,就将其挂起。

原理:方法不支持事务,即使调用者有事务,也不会参与。

示例

|------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 | @Transactional(propagation = Propagation.REQUIRED) public void methodA() { // 执行数据库操作 methodB(); } @Transactional(propagation = Propagation.NOT_SUPPORTED) public void methodB() { // 执行数据库操作 } |

分析methodA 的事务会在执行 methodB 时被挂起,methodB 以非事务方式执行,执行完毕后恢复 methodA 的事务。

3.5 MANDATORY {#3-5-MANDATORY}

定义:支持当前事务,必须存在一个事务,否则抛出异常。

原理 :如果调用者有事务,方法参与;否则,抛出 IllegalTransactionStateException

示例

|------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 | @Transactional(propagation = Propagation.REQUIRED) public void methodA() { // 执行数据库操作 methodB(); } @Transactional(propagation = Propagation.MANDATORY) public void methodB() { // 执行数据库操作 } |

分析 :当 methodA 调用 methodB 时,由于 methodA 有事务,methodB 可以正常参与事务。如果 methodB 被独立调用,无事务,会抛出异常。

3.6 NEVER {#3-6-NEVER}

定义:以非事务方式执行,如果存在事务,则抛出异常。

原理:方法绝不支持事务,确保其执行不在事务上下文中。

示例

|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 | @Transactional(propagation = Propagation.REQUIRED) public void methodA() { // 执行数据库操作 methodB(); } @Transactional(propagation = Propagation.NEVER) public void methodB() { // 执行数据库操作 } |

分析 :当 methodA 调用 methodB 时,由于 methodA 有事务,调用 methodB 会抛出异常。如果 methodB 被独立调用,无事务,则正常执行。

3.7 NESTED {#3-7-NESTED}

定义 :如果存在事务,则在嵌套事务内执行;否则,类似于 REQUIRED

原理:基于底层数据库的保存点(savepoint),允许在嵌套事务中回滚到保存点,而不影响外部事务。

示例

|---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | 1 2 3 4 5 6 7 8 9 10 11 | @Transactional(propagation = Propagation.REQUIRED) public void methodA() { // 执行数据库操作 methodB(); // 继续执行 } @Transactional(propagation = Propagation.NESTED) public void methodB() { // 执行数据库操作 } |

分析 :如果 methodB 出现异常且事务被回滚,只会回滚到 methodB 的开始,而 methodA 的事务仍然可以继续或回滚。

  1. 传播行为对比 {#4-传播行为对比} =====================

| 传播行为 | 是否必须存在事务 | 是否开启新事务 | 是否挂起现有事务 | 适用场景 | |---------------|----------|---------|----------|-----------------------------| | REQUIRED | 否 | 否 | 否 | 默认行为,绝大多数场景使用,如服务层方法。 | | REQUIRES_NEW | 否 | 是 | 是 | 需要独立事务,如日志记录,不受外部事务影响。 | | SUPPORTS | 否 | 否 | 否 | 可选事务性,读操作等,既能在事务中也能在非事务中运行。 | | NOT_SUPPORTED | 否 | 否 | 是 | 非事务操作,如与事务无关的外部系统交互。 | | MANDATORY | 是 | 否 | 否 | 强制要求存在事务的操作,确保方法调用在事务环境中。 | | NEVER | 否 | 否 | 是 | 确保方法在非事务环境中执行,避免事务上下文。 | | NESTED | 否 | 基于底层支持 | 否 | 需要在事务内进行部分回滚的场景,如复杂业务操作。 |

4.1 关键差异点 {#4-1-关键差异点}

  • 是否开启新事务REQUIRES_NEWNESTED 可以开启新事务,其他大部分属于参与现有事务或非事务。

  • 是否必须存在事务MANDATORYNEVER 针对事务的存在有严格要求。

  • 是否挂起现有事务REQUIRES_NEWNOT_SUPPORTED 会挂起当前事务。

  • 嵌套事务支持NESTED 依赖于底层数据库的 savepoint 支持,允许在同一事务中进行局部回滚。

  1. 实际应用中的选择 {#5-实际应用中的选择} =========================
  • 大多数场景 :使用 REQUIRED 是最合适的选择,因为它简化了事务管理,并且大多数情况下方法需要参与到调用者的事务中。

  • 独立事务需求 :如日志记录、发送通知等,需要与主事务独立的操作,可以使用 REQUIRES_NEW

  • 可选事务 :对于既能在事务中运行也能在非事务中运行的操作,可以使用 SUPPORTS

  • 确保非事务执行 :若某操作必须在非事务环境下执行,如一些特定的外部系统调用,可以使用 NOT_SUPPORTEDNEVER

  • 强制要求事务 :在某些关键业务逻辑中,确保方法只能在事务中调用,可以使用 MANDATORY

  • 局部回滚需求 :在复杂业务场景下,需要对某部分操作进行局部回滚,可以考虑使用 NESTED,但需确保底层数据库支持。

  1. 注意事项 {#6-注意事项} =================
  • 数据库支持 :部分传播行为(如 NESTED)依赖于底层数据库的支持,使用前需要确认数据库和事务管理器的兼容性。

  • 事务管理器配置 :正确配置 Spring 事务管理器(如 PlatformTransactionManager)对于事务传播行为的正常工作至关重要。

  • 事务边界设计:合理设计事务边界,避免过长的事务导致资源占用和性能问题。

  1. 总结 {#7-总结} =============

理解 Spring 事务传播行为对于构建健壮的事务管理策略至关重要。通过合理选择合适的传播行为,可以确保在复杂的业务逻辑和调用链中,数据的一致性和系统的稳定性。开发人员应根据具体的业务需求和应用场景,灵活运用不同的传播行为,以达到最佳的事务管理效果。

  1. 学习交流 {#8-学习交流} =================
赞(1)
未经允许不得转载:工具盒子 » Spring 有哪几种事务传播行为?它们有什么区别?