Java-138 深入浅出 MySQL Spring Boot 事务传播机制全解析:从 REQUIRED 到 NESTED 的实战详解 传播机制原理

点一下关注吧!!!非常感谢!!持续更新!!!

🚀 AI篇持续更新中!(长期更新)

AI炼丹日志-31- 千呼万唤始出来 GPT-5 发布!"快的模型 + 深度思考模型 + 实时路由",持续打造实用AI工具指南!📐🤖

💻 Java篇正式开启!(300篇)

目前2025年09月29日更新到:
Java-136 深入浅出 MySQL Spring Boot @Transactional 使用指南:事务传播、隔离级别与异常回滚策略

MyBatis 已完结,Spring 已完结,Nginx已完结,Tomcat已完结,分布式服务正在更新!深入浅出助你打牢基础!

📊 大数据板块已完成多项干货更新(300篇):

包括 Hadoop、Hive、Kafka、Flink、ClickHouse、Elasticsearch 等二十余项核心组件,覆盖离线+实时数仓全栈!
大数据-278 Spark MLib - 基础介绍 机器学习算法 梯度提升树 GBDT案例 详解

事务传播

参考来源

简单介绍

(对应注解的:propagation)事务的传播行为,是指程序在调用的过程中,如果调用方已经创建了事务,那么被调用的服务将如何处理事务的一种特征,如下图所示:

PROPAGATION_REQUIRED

这是注解默认的值,它具有以下的特点:

● 如果当前没有物理事务,那么 Spring 会创建一个事务出来

● 如果已经有了一个物理事务,那么就加入这个事务

● 每一个 PROGAGATION_REQUIRED 都对应一个逻辑事务,这些逻辑事务都会加入到同一个物理事务

● 每个逻辑事务都有自己的作用范围,但是在这种传播机制下,所有这些范围都会被映射到同一个物理事务中

正是因为所有的逻辑事务都在同一个物理事务上,当物理事务上任何一个逻辑进行回滚,那么这个物理事务就会回滚。

PROPAGATION_REQUIRES_NEW

PROPAGATION_REQUIRES_NEW 是 Spring 事务传播行为中的一种重要级别,它表示无论当前是否存在事务,Spring 总会创建一个新的独立的物理事务。在这种传播级别下,内部事务与外部事务完全隔离,具有以下关键特性:

  1. 独立事务特性

    • 内部事务会启动一个全新的数据库连接
    • 拥有独立的事务ID
    • 使用独立的事务隔离级别
    • 维护自身的事务状态
  2. 与外部事务的关系

    • 如果外部事务存在,会先将其挂起
    • 内部事务完成后才会恢复外部事务
    • 内部事务的提交或回滚不会影响外部事务
  3. 典型应用场景

java 复制代码
   @Transactional(propagation = Propagation.REQUIRED)
   public void outerMethod() {
       // 外部事务操作...
       innerMethod();  // 调用内嵌方法
       // 更多外部事务操作...
   }

   @Transactional(propagation = Propagation.REQUIRES_NEW)
   public void innerMethod() {
       // 这些操作会在独立的事务中执行
   }
  1. 注意事项

    • 每个 REQUIRES_NEW 事务都会占用新的数据库连接
    • 可能导致连接池资源紧张
    • 适合用于需要独立提交的日志记录、审计等非核心业务
  2. 与其他传播行为的区别

    • 不同于 PROPAGATION_REQUIRED(加入当前事务)
    • 不同于 PROPAGATION_NESTED(嵌套事务)
    • 不同于 PROPAGATION_NOT_SUPPORTED(非事务执行)

这种传播级别特别适合那些需要确保执行成功,且执行结果不应影响主业务流程的操作场景。

这种情况下,每个物理事务都有自己的数据库连接,也就是说,当创建内部物理事务的时候,会同步为这个事务绑定一个新的数据库连接,当内部的物理事务运行的时候,外部的物理事务就会暂停执行(保持连接),当内部的物理事务提交之后,外部的事务进行回复,继续执行或者回滚。

(这种情况下,即使内部的物理事务回滚了,外部的事务也可以顺利提交执行;如果外部事务回滚了,也不会影响内部的事务提交执行。)

PROPAGATION_NESTED

PROPAGATION_NESTED 是 Spring 事务传播机制中的一种特殊传播行为,它与 PROPAGATION_REQUIRED 类似,但具有更精细的回滚控制能力。

主要特点:

  1. 如果当前存在事务,则创建一个嵌套事务(内部事务),该嵌套事务会设置一个 SAVEPOINT(保存点)
  2. 嵌套事务的回滚不会影响外部事务,只会回滚到保存点位置
  3. 外部事务的回滚会导致嵌套事务也回滚
  4. 如果当前没有事务,则与 PROPAGATION_REQUIRED 行为相同

典型应用场景:

  • 需要记录操作日志的场景(日志记录失败不应影响主业务)
  • 批量处理中的单条记录处理(某条记录处理失败不应中断整个批次)
  • 需要部分回滚的复杂业务逻辑

示例:

java 复制代码
@Transactional(propagation = Propagation.REQUIRED)
public void batchProcess() {
    // 主业务逻辑
    for (Item item : items) {
        try {
            processItem(item); // 嵌套事务处理单条记录
        } catch (Exception e) {
            // 单条记录失败不影响其他记录
            log.error("Process item failed", e);
        }
    }
}

@Transactional(propagation = Propagation.NESTED)
public void processItem(Item item) {
    // 处理单条记录的业务逻辑
}

注意事项:

  1. 嵌套事务与 JDBC 3.0 的保存点机制实现相关
  2. 不是所有数据库都支持保存点机制
  3. JTA 事务管理器不支持此传播行为

PROPAGATION_MANDATORY

PROPAGATION_MANDATORY 是 Spring 事务传播行为中的一种,表示当前方法必须在一个已存在的物理事务中运行。如果当前没有活动的事务,将会抛出 IllegalTransactionStateException 异常。

主要特点

  1. 事务依赖性:该方法不能独立运行,必须依赖于调用方提供的事务上下文
  2. 异常机制:如果没有活动事务,会立即抛出异常而不是创建一个新事务
  3. 事务继承:会沿用调用方的事务属性(如隔离级别、超时设置等)

典型应用场景

  • 核心业务方法:如资金转账操作必须在一个事务中执行
  • 数据一致性要求高的操作:如订单系统中的库存扣减
  • 作为更大事务的一部分:如电子商务中的支付流程

代码示例

java 复制代码
@Service
public class PaymentService {
    @Transactional(propagation = Propagation.MANDATORY)
    public void processPayment(Order order) {
        // 支付处理逻辑
        // 如果这个方法被没有事务的代码调用,会抛出异常
    }
}

与其他传播行为的区别

  • 与 REQUIRED 不同:REQUIRED 在没有事务时会新建一个,而 MANDATORY 会抛出异常
  • 与 SUPPORTS 不同:SUPPORTS 可以在没有事务时运行,而 MANDATORY 必须有事务
  • 与 NEVER 相反:NEVER 要求不能有事务,MANDATORY 要求必须有事务

注意事项

  1. 适用于需要强制事务保障的重要业务方法
  2. 调用方必须确保已经开启了事务
  3. 可以配合其他事务属性(如隔离级别、只读标记)一起使用

PROPAGATION_NEVER

定义与作用

PROPAGATION_NEVER 是 Spring 事务传播行为中的一种策略,表示方法必须在非事务环境下执行。如果当前已经存在事务上下文,Spring 将直接抛出 IllegalTransactionStateException 异常,强制中止操作。

典型特征

  1. 严格非事务要求:被标记的方法必须确保在没有任何事务(包括物理事务和嵌套事务)的环境中运行
  2. 显式异常提示 :与 PROPAGATION_NOT_SUPPORTED 不同,它不会挂起已有事务,而是直接拒绝执行
  3. 事务边界检查:在方法执行前会进行严格的事务存在性检查

使用场景

  • 执行不需要事务的读取操作(如缓存加载)
  • 运行明确不能有事务影响的特殊方法(如某些审计日志记录)
  • 在事务边界外执行统计计算等操作
  • 作为事务与非事务代码之间的显式隔离标记

代码示例

java 复制代码
@Transactional(propagation = Propagation.NEVER)
public void loadReferenceData() {
    // 此方法必须确保在无事务环境下执行
    cacheManager.reloadAll();
}

注意事项

  1. 调用链上必须确保没有 @Transactional 注解的传播
  2. 需要与事务模板(TransactionTemplate)等显式事务操作隔离使用
  3. 在测试环境中需要特别注意模拟非事务环境
  4. REQUIRES_NEW 等事务传播行为组合使用时会产生冲突

异常处理

当检测到现有事务时,Spring 会抛出:

复制代码
org.springframework.transaction.IllegalTransactionStateException: 
Existing transaction found for transaction marked with propagation 'never'

建议在调用方做好异常捕获和处理逻辑,或者通过前置条件检查确保执行环境符合要求。

PROPAGATION_SUPPORTS

PROPAGATION_SUPPORTS 是 Spring 事务传播机制中的一种传播行为,它定义了方法在事务上下文中的执行方式。具体行为规则如下:

  1. 存在物理事务时

    • 如果当前已经存在一个事务上下文(即调用方法处于一个事务范围内),则该方法会加入这个现有的事务
    • 此时方法的所有操作都将成为现有事务的一部分,遵循现有事务的隔离级别和超时设置
    • 如果外层事务回滚,该方法所做的所有修改也会被回滚
  2. 不存在物理事务时

    • 如果当前没有事务上下文,则该方法会以非事务的方式执行
    • 每个数据库操作都会自动提交,不会参与任何事务管理
    • 此时方法执行的SQL语句将具有自动提交的特性

典型应用场景

  • 适用于那些既可以在事务中运行,也可以不在事务中运行的非核心业务方法
  • 常用于查询操作,因为查询通常不需要事务支持
  • 适合作为服务层方法的默认传播行为,特别是那些不涉及数据修改的操作

示例代码

java 复制代码
@Service
public class UserService {
    @Transactional(propagation = Propagation.SUPPORTS)
    public User getUserById(Long id) {
        // 该方法可以在事务中执行,也可以不在事务中执行
        return userRepository.findById(id);
    }
}

注意事项

  • 当方法中存在多个数据库操作时,使用PROPAGATION_SUPPORTS可能导致数据不一致的风险
  • 不适合用于必须保证原子性的关键业务操作
  • PROPAGATION_REQUIRED不同,它不会主动创建新的事务

与其他传播行为的比较

  • PROPAGATION_REQUIRED更灵活,不会强制要求事务
  • PROPAGATION_NOT_SUPPORTED更温和,允许在存在事务时参与其中
  • PROPAGATION_MANDATORY相反,后者要求必须存在事务

PROPAGATION_NOT_SUPPORTED

PROPAGATION_NOT_SUPPORTED 是 Spring 事务传播行为中的一种特殊模式,它表示当前方法不应在事务上下文中运行。当使用此传播行为时:

  1. 事务挂起机制

    • 如果调用此方法时已经存在一个活动事务(物理事务),Spring 会将该事务挂起(suspend)
    • 事务管理器会将该事务的相关资源(如数据库连接)与当前线程解绑
    • 事务状态信息会被保存在内存中,以便后续恢复
  2. 非事务执行

    • 方法会在没有事务的上下文中执行
    • 所有数据库操作将以自动提交模式(auto-commit)运行
    • 每个SQL语句都将被立即提交,不会参与任何事务
  3. 事务恢复

    • 方法执行完毕后,Spring会检查是否有被挂起的事务
    • 如果有,会将之前挂起的事务恢复(resume)
    • 事务资源会重新绑定到当前线程
    • 后续操作将继续在原有事务上下文中执行

典型应用场景

  • 日志记录操作:当需要记录日志到数据库,但不希望日志记录操作影响主业务事务时
  • 非关键性操作:如发送通知消息等非核心业务操作
  • 性能优化:某些不需要事务保证的只读操作,可以避免事务开销

示例代码

java 复制代码
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void logOperation(String message) {
    // 此方法会在非事务上下文中执行
    logRepository.save(new LogEntry(message));
}

注意事项

  • 使用此传播行为时,方法中的数据库操作将不具备原子性
  • 要谨慎使用,确保业务确实不需要事务保证
  • 在分布式事务环境中行为可能更加复杂
相关推荐
snpgroupcn2 小时前
SAP S/4HANA迁移方法选哪种?选择性数据转换是否合适?企业需要考虑哪些关键因素!
运维·数据库·云计算
码神本神3 小时前
【附源码】基于Spring Boot的高校爱心捐助平台的设计与实现
java
真的想不出名儿3 小时前
登录前验证码校验实现
java·前端·python
珹洺3 小时前
Java-Spring入门指南(十九)thymeleaf基本概念
java·spring·状态模式
吹晚风吧3 小时前
什么是跨域?跨域怎么解决?跨域解决的是什么问题?
java·vue.js·js·cors
敲码图一乐3 小时前
流量安全——基于Sentinel实现限流,熔断,降级
java·开发语言·数据库
0xMinos3 小时前
Java 设计模式——单例模式
java·设计模式
孟意昶3 小时前
Spark专题-第三部分:性能监控与实战优化(2)-分区优化
大数据·分布式·sql·性能优化·spark·big data
zzywxc7873 小时前
AI赋能千行百业:金融、医疗、教育、制造业的落地实践与未来展望
java·人工智能·python·microsoft·金融·golang·prompt