当前位置: 首页 > news >正文

全面解读 @Transactional 的传播机制:一次搞懂 Spring 事务的各种“传播方式”!

文章目录

      • **一、REQUIRED(默认)**
        • **代码示例**
      • **二、REQUIRES_NEW**
        • **代码示例**
      • **三、NESTED**
        • **代码示例**
      • **四、SUPPORTS**
        • **代码示例**
      • **五、NOT_SUPPORTED**
        • **代码示例**
      • **六、MANDATORY**
        • **代码示例**
      • **七、NEVER**
        • **代码示例**
      • **总结**
      • 推荐阅读文章

正文

在开发中,我们使用 Spring 的 @Transactional 注解管理事务,而 Propagation(传播机制)正是 @Transactional 注解中的一个关键配置。Propagation 决定了当前方法的事务如何与已有事务交互,是控制事务嵌套行为的重要参数。但因为涉及多个选项和一些细微的差异,传播机制总给人“雾里看花”的感觉。

今天,我用简单通俗的方式来带你一探究竟,顺便配上代码案例,让你对 Propagation 的每种传播方式都理解得一清二楚。让我们开始吧!


一、REQUIRED(默认)

REQUIRED@Transactional 的默认传播机制。它的规则是:如果当前存在事务,则加入该事务;否则创建一个新的事务

代码示例
@Service
public class UserService {@Transactional(propagation = Propagation.REQUIRED)public void registerUser() {// 主方法addUser();sendWelcomeEmail();}@Transactional(propagation = Propagation.REQUIRED)public void addUser() {// 向数据库添加用户}@Transactional(propagation = Propagation.REQUIRED)public void sendWelcomeEmail() {// 发送欢迎邮件}
}

效果分析
在上面的代码中,registerUser() 调用了 addUser()sendWelcomeEmail() 方法。因为 REQUIRED 传播机制的规则是加入当前事务,所以 registerUser() 方法中的三个事务会共享同一个事务。也就是说,如果 sendWelcomeEmail() 发送失败,整个 registerUser() 事务会回滚。


二、REQUIRES_NEW

REQUIRES_NEW 的规则是:不管当前是否有事务,都创建一个新的事务,并将当前事务挂起。适合在方法中调用一些独立事务的操作。

代码示例
@Service
public class UserService {@Transactional(propagation = Propagation.REQUIRED)public void registerUser() {addUser();sendWelcomeEmail();}@Transactional(propagation = Propagation.REQUIRES_NEW)public void addUser() {// 向数据库添加用户}@Transactional(propagation = Propagation.REQUIRES_NEW)public void sendWelcomeEmail() {// 发送欢迎邮件}
}

效果分析
在这个案例中,registerUser() 方法会调用 addUser()sendWelcomeEmail(),并且它们各自都有独立的事务。即使 sendWelcomeEmail() 抛出异常,也不会影响 addUser() 的事务提交。适合场景:某些方法需要独立事务的情形,比如记录用户日志。


三、NESTED

NESTED 的规则是:如果当前存在事务,则在当前事务中创建一个嵌套事务;否则创建一个新的事务。这种传播机制类似于“保存点”机制,即使嵌套事务失败,外部事务也可以选择回滚到嵌套事务之前的状态。

代码示例
@Service
public class UserService {@Transactional(propagation = Propagation.REQUIRED)public void registerUser() {addUser();updateUserDetails();}@Transactional(propagation = Propagation.NESTED)public void addUser() {// 向数据库添加用户}@Transactional(propagation = Propagation.REQUIRED)public void updateUserDetails() {// 更新用户详细信息}
}

效果分析
在这个例子中,如果 addUser() 的嵌套事务失败,主事务可以选择回滚到 addUser() 之前的状态,而无需回滚整个 registerUser() 事务。它适合场景如部分业务逻辑出错但希望主事务继续的情况。


四、SUPPORTS

SUPPORTS 的规则是:如果当前存在事务,则加入当前事务;否则以非事务方式执行。适合一些对事务要求不严格的操作。

代码示例
@Service
public class UserService {@Transactional(propagation = Propagation.REQUIRED)public void registerUser() {addUser();optionalLog();}@Transactional(propagation = Propagation.SUPPORTS)public void optionalLog() {// 记录非关键日志信息}
}

效果分析
这里,optionalLog() 方法会在 registerUser() 事务范围内执行;若没有事务,则会以非事务方式执行。这种机制非常适合一些非关键的操作,或对于事务一致性要求不高的场景。


五、NOT_SUPPORTED

NOT_SUPPORTED 的规则是:不支持事务,如果当前存在事务,则挂起该事务,转而以非事务方式执行

代码示例
@Service
public class UserService {@Transactional(propagation = Propagation.REQUIRED)public void registerUser() {addUser();nonTransactionalOperation();}@Transactional(propagation = Propagation.NOT_SUPPORTED)public void nonTransactionalOperation() {// 执行非事务操作}
}

效果分析
在此例中,nonTransactionalOperation() 将以非事务方式执行,即使 registerUser() 的事务出现错误,该操作也不会回滚。通常用于一些不会影响数据一致性的操作,比如缓存清理。


六、MANDATORY

MANDATORY 的规则是:必须在一个已有事务中运行,否则抛出异常。适合某些关键的操作,确保不会意外在非事务环境中运行。

代码示例
@Service
public class UserService {@Transactional(propagation = Propagation.REQUIRED)public void registerUser() {criticalOperation();}@Transactional(propagation = Propagation.MANDATORY)public void criticalOperation() {// 关键的事务操作}
}

效果分析
在这里,criticalOperation() 必须在事务中调用,否则会抛出异常。它适合在需要高度数据一致性的场景下使用,确保不会意外在非事务环境下执行。


七、NEVER

NEVER 的规则是:永远不在事务环境中运行,如果当前存在事务,则抛出异常

代码示例
@Service
public class UserService {public void performOperation() {nonTransactionalOperation();}@Transactional(propagation = Propagation.NEVER)public void nonTransactionalOperation() {// 永远不在事务中执行的操作}
}

效果分析
nonTransactionalOperation() 会确保自己不运行在事务中。如果调用时有事务存在,将抛出异常。适合用于不需要事务且影响较小的操作,如日志系统。


总结

Spring 的 Propagation 传播机制给了我们极大的灵活性,使得事务的控制不再“一刀切”。每种传播方式都有其适用场景,因此了解它们的区别和使用方式,能够让我们的代码更加可靠和高效。

希望这篇文章能让大家对 @Transactional 的传播机制有更深刻的认识!

推荐阅读文章

  • 由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)
  • 如何理解 HTTP 是无状态的,以及它与 Cookie 和 Session 之间的联系
  • HTTP、HTTPS、Cookie 和 Session 之间的关系
  • 使用 Spring 框架构建 MVC 应用程序:初学者教程
  • 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误
  • Java Spring 中常用的 @PostConstruct 注解使用总结
  • 线程 vs 虚拟线程:深入理解及区别
  • 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别
  • 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!
  • 探索 Lombok 的 @Builder 和 @SuperBuilder:避坑指南(一)
  • 为什么用了 @Builder 反而报错?深入理解 Lombok 的“暗坑”与解决方案(二)

http://www.mrgr.cn/news/59177.html

相关文章:

  • 基于Springboot的图书个性化推荐系统【源码】+【论文】
  • gin入门教程(10):实现jwt认证
  • P1496 火烧赤壁
  • logback 如何将日志输出到文件
  • Python依赖库的几种离线安装方法
  • 【linux】服务器Ubuntu20.04安装cuda11.8教程
  • 常用设计模式...
  • 【Vulnhub靶场】DC-4
  • 2024高等代数【南昌大学】
  • 用kali入侵 DarkHole_2测试
  • 小白直接冲!一区蛇群优化算法+双向深度学习+注意力机制!SO-BiTCN-BiGRU-Attention多输入单输出回归预测
  • 安全见闻-web安全
  • 【Vue 3】全面解析Composition API的实战技巧
  • Python 从入门到实战40(数据分析概述)
  • C# async-await循环依赖梳理
  • 第四期书生大模型实战营(【入门岛】- 第2关 | Python 基础知识 )
  • 【Linux】SQLite 数据库安装教程(Ubuntu 22.04)
  • Linux之web服务器
  • 快捷键记忆
  • 变频器启动、停止、正/反转控制电路原理详解
  • Leecode热题100-287.寻找重复数
  • 实测体验Claude 3.5升级版:AI首次实现直接操控电脑!
  • Pyside6 布局管理器(3)--- QGridLayout的使用
  • Python使用unrar遇到的问题及解决
  • API网关的作用--为什么微服务需要一个API网关?
  • 计算机网络中网络层发送报文时IP地址的变化,交换器的广播功能及相关设备功能