一文吃透 Spring 事务传播行为:7 种场景+代码实战

news/2026/1/17 14:31:21/文章来源:https://www.cnblogs.com/sun-10387834/p/19493742

作为后端开发,Spring 事务是日常工作的基础,但不少人只会用 @Transactional 注解加个 rollbackFor,对底层的事务传播行为一知半解。直到遇到“嵌套调用事务不回滚”“重复提交导致数据异常”等问题,才发现对传播行为的理解不足会踩大坑。

其实事务传播行为的核心很简单:当一个带有事务的方法,调用另一个方法时,如何决定新方法的事务边界(是复用当前事务,还是新建事务,或是不参与事务)。Spring 定义了 7 种标准传播行为,本文结合实际业务场景,逐一拆解每种行为的用法、代码示例和适用场景,帮你彻底吃透。

先铺垫两个基础前提,避免理解偏差:

  • 所有示例基于 Spring Boot 2.x+,依赖 spring-boot-starter-data-jpamybatis-plus(本文用 JPA 简化数据库操作);

  • 事务传播行为仅对 @Transactional 注解修饰的方法生效,且必须通过 Spring 代理调用(同类方法内部调用需注意代理失效问题)。

一、Spring 7 种事务传播行为全解析

Spring 事务传播行为通过 propagation 属性配置,默认值为 REQUIRED。下面按“日常使用率”排序,逐一讲解。

1. REQUIRED(默认):如果有事务就复用,没有就新建

核心逻辑:这是最常用的传播行为,遵循“能复用则复用,无则新建”的原则。如果调用方已经存在事务,被调用方就加入当前事务,两者共用一个事务边界(要么一起提交,要么一起回滚);如果调用方没有事务,被调用方就新建一个独立事务。

业务场景:绝大多数核心业务流程,比如“创建订单+扣减库存”,两者必须在同一事务中,要么都成功,要么都失败。

代码示例

@Service
public class OrderService {@Autowiredprivate OrderRepository orderRepository;@Autowiredprivate StockService stockService;// 调用方:带有事务@Transactional(rollbackFor = Exception.class)public void createOrder(Long productId, Integer count, Long userId) {// 1. 创建订单Order order = new Order();order.setProductId(productId);order.setCount(count);order.setUserId(userId);order.setStatus(1); // 待支付orderRepository.save(order);// 2. 调用扣减库存方法(复用当前事务)stockService.deductStock(productId, count);}
}@Service
public class StockService {@Autowiredprivate StockRepository stockRepository;// 被调用方:传播行为为 REQUIRED(默认,可省略)@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)public void deductStock(Long productId, Integer count) {Stock stock = stockRepository.findByProductId(productId).orElseThrow(() -> new RuntimeException("库存不存在"));if (stock.getCount() < count) {throw new RuntimeException("库存不足");}stock.setCount(stock.getCount() - count);stockRepository.save(stock);}
}

结果说明

  • 如果 deductStock 抛出异常(如库存不足),createOrder 的订单创建操作会一起回滚,不会出现“有订单无库存扣减”的脏数据;

  • 如果调用方 createOrder 没有加 @TransactionaldeductStock 会新建独立事务,仅库存扣减操作受事务控制。

2. SUPPORTS:如果有事务就复用,没有就无事务

核心逻辑:被调用方“被动”参与事务,不主动创建事务。如果调用方有事务,就加入其中;如果调用方没有事务,就以无事务方式执行。

业务场景:查询类方法,既可以在事务中执行(保证查询到未提交的事务数据,如分布式事务中的一致性查询),也可以独立执行(普通查询场景)。

代码示例

@Service
public class OrderQueryService {@Autowiredprivate OrderRepository orderRepository;// 传播行为为 SUPPORTS,不主动创建事务@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)public Order getOrderById(Long orderId) {return orderRepository.findById(orderId).orElseThrow(() -> new RuntimeException("订单不存在"));}
}// 调用场景1:调用方有事务
@Service
public class OrderOperateService {@Autowiredprivate OrderQueryService queryService;@Transactional(rollbackFor = Exception.class)public void updateOrderStatus(Long orderId, Integer status) {// 复用当前事务查询订单(能查询到未提交的临时数据)Order order = queryService.getOrderById(orderId);order.setStatus(status);orderRepository.save(order);}
}// 调用场景2:调用方无事务
@Controller
public class OrderController {@Autowiredprivate OrderQueryService queryService;@GetMapping("/order/{id}")public ResponseEntity<Order> getOrder(@PathVariable Long id) {// 无事务方式执行查询return ResponseEntity.ok(queryService.getOrderById(id));}
}

注意点:SUPPORTS 修饰的方法如果在无事务环境下执行,所有数据库操作都是自动提交的,无法回滚。

3. MANDATORY:必须在已有事务中执行,否则抛异常

核心逻辑:被调用方强制要求调用方有事务,自身不新建事务。如果调用方没有事务,直接抛出 IllegalTransactionStateException 异常,拒绝执行。

业务场景:必须依赖调用方事务的操作,比如“订单状态变更日志记录”,必须和订单状态变更在同一事务中,确保日志与业务操作一致,不允许独立执行。

代码示例

@Service
public class OrderLogService {@Autowiredprivate OrderLogRepository logRepository;// 必须在已有事务中执行,否则抛异常@Transactional(propagation = Propagation.MANDATORY, rollbackFor = Exception.class)public void recordLog(Long orderId, Integer oldStatus, Integer newStatus) {OrderLog log = new OrderLog();log.setOrderId(orderId);log.setOldStatus(oldStatus);log.setNewStatus(newStatus);log.setOperateTime(LocalDateTime.now());logRepository.save(log);}
}// 正确调用:调用方有事务
@Service
public class OrderService {@Autowiredprivate OrderLogService logService;@Transactional(rollbackFor = Exception.class)public void updateOrderStatus(Long orderId, Integer newStatus) {Order order = orderRepository.findById(orderId).orElseThrow();Integer oldStatus = order.getStatus();order.setStatus(newStatus);orderRepository.save(order);// 正常执行,复用当前事务logService.recordLog(orderId, oldStatus, newStatus);}// 错误调用:调用方无事务public void errorUpdateStatus(Long orderId, Integer newStatus) {// 调用 recordLog 时会抛 IllegalTransactionStateExceptionlogService.recordLog(orderId, 1, newStatus);}
}

4. REQUIRES_NEW:无论是否有事务,都新建独立事务

核心逻辑:被调用方强制新建一个独立事务,与调用方事务完全隔离(两个事务互不影响,各自提交/回滚)。如果调用方已有事务,会先暂停当前事务,待新事务执行完成后,再恢复原事务。

业务场景:需要独立存在的操作,比如“订单创建失败后记录异常日志”,即使订单创建事务回滚,日志也必须保留,不能被回滚影响。

代码示例

@Service
public class OrderErrorLogService {@Autowiredprivate OrderErrorLogRepository errorLogRepository;// 新建独立事务,与调用方事务隔离@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)public void recordErrorLog(Long productId, Integer count, String errorMsg) {OrderErrorLog errorLog = new OrderErrorLog();errorLog.setProductId(productId);errorLog.setCount(count);errorLog.setErrorMsg(errorMsg);errorLog.setCreateTime(LocalDateTime.now());errorLogRepository.save(errorLog);}
}@Service
public class OrderService {@Autowiredprivate OrderErrorLogService errorLogService;@Transactional(rollbackFor = Exception.class)public void createOrder(Long productId, Integer count, Long userId) {try {// 模拟订单创建失败(如库存不足)throw new RuntimeException("订单创建失败:库存不足");} catch (Exception e) {// 记录错误日志,新建独立事务,即使当前事务回滚,日志也会保留errorLogService.recordErrorLog(productId, count, e.getMessage());// 重新抛出异常,让当前事务回滚throw e;}}
}

结果说明createOrder 事务回滚,但 recordErrorLog 新建的独立事务会正常提交,错误日志成功保存,实现“业务回滚但日志留存”的需求。

5. NOT_SUPPORTED:无论是否有事务,都以无事务方式执行

核心逻辑:被调用方拒绝参与任何事务。如果调用方有事务,会先暂停当前事务,待被调用方无事务执行完成后,再恢复原事务;如果调用方无事务,直接正常执行。

业务场景:不需要事务的耗时操作,比如“订单创建后发送短信通知”,即使通知失败,也不能影响订单创建事务的提交;或者不允许在事务中执行的操作(如批量数据同步,避免长时间占用事务资源)。

代码示例

@Service
public class SmsService {// 拒绝参与事务,以无事务方式执行@Transactional(propagation = Propagation.NOT_SUPPORTED)public void sendOrderSms(Long userId, Long orderId) {// 模拟短信发送(耗时操作,无事务)try {Thread.sleep(1000);System.out.println("向用户" + userId + "发送订单" + orderId + "创建成功短信");} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new RuntimeException("短信发送失败");}}
}@Service
public class OrderService {@Autowiredprivate SmsService smsService;@Transactional(rollbackFor = Exception.class)public void createOrder(Long productId, Integer count, Long userId) {// 1. 创建订单(事务内操作)Order order = new Order();// ... 订单赋值逻辑orderRepository.save(order);// 2. 发送短信(无事务,即使失败也不影响订单提交)try {smsService.sendOrderSms(userId, order.getId());} catch (Exception e) {// 仅记录异常,不回滚订单事务System.err.println("短信发送失败:" + e.getMessage());}}
}

6. NEVER:必须在无事务环境下执行,否则抛异常

核心逻辑:被调用方严格禁止在事务中执行。如果调用方有事务,直接抛出 IllegalTransactionStateException 异常;如果调用方无事务,正常执行。

业务场景:完全不允许事务控制的操作,比如“数据归档脚本”“第三方接口调用(自身已保证幂等)”,避免事务长时间占用资源或导致数据一致性问题。

代码示例

@Service
public class DataArchiveService {// 必须无事务执行,有事务则抛异常@Transactional(propagation = Propagation.NEVER)public void archiveOldOrder(LocalDateTime endTime) {// 模拟归档3个月前的订单数据(无事务,避免长时间锁表)List<Order> oldOrders = orderRepository.findByCreateTimeBefore(endTime);// ... 归档逻辑}
}// 错误调用:调用方有事务
@Service
public class OrderService {@Autowiredprivate DataArchiveService archiveService;@Transactional(rollbackFor = Exception.class)public void doArchive() {// 调用 archiveOldOrder 时会抛异常,因为当前有事务archiveService.archiveOldOrder(LocalDateTime.now().minusMonths(3));}
}

7. NESTED:嵌套事务,依赖调用方事务

核心逻辑:被调用方在调用方事务内创建一个“嵌套子事务”,子事务依赖于父事务(调用方事务)。父事务提交时,子事务才会提交;父事务回滚时,子事务必然回滚;但子事务回滚时,父事务可以选择继续执行(不会被子事务回滚影响)。

注意:嵌套事务依赖数据库支持(如 MySQL 的 SAVEPOINT 保存点机制),并非所有数据库都支持;与 REQUIRES_NEW 的区别是:NESTED 是子事务,与父事务同属一个事务上下文;REQUIRES_NEW 是完全独立的事务。

业务场景:父事务中包含可选操作,子事务失败不影响父事务核心逻辑,比如“创建订单时尝试扣减优惠券”,优惠券扣减失败(子事务回滚),但订单创建(父事务)可以继续执行。

代码示例

@Service
public class CouponService {@Autowiredprivate CouponRepository couponRepository;// 嵌套事务,依赖调用方事务@Transactional(propagation = Propagation.NESTED, rollbackFor = Exception.class)public void deductCoupon(Long couponId, Long userId) {Coupon coupon = couponRepository.findByIdAndUserId(couponId, userId).orElseThrow(() -> new RuntimeException("优惠券不存在"));if (coupon.getIsUsed()) {throw new RuntimeException("优惠券已使用");}coupon.setIsUsed(true);couponRepository.save(coupon);}
}@Service
public class OrderService {@Autowiredprivate CouponService couponService;@Transactional(rollbackFor = Exception.class)public void createOrder(Long productId, Integer count, Long userId, Long couponId) {// 1. 创建订单(父事务核心逻辑)Order order = new Order();// ... 订单赋值逻辑orderRepository.save(order);// 2. 尝试扣减优惠券(子事务,失败不影响订单)try {couponService.deductCoupon(couponId, userId);} catch (Exception e) {// 子事务回滚,父事务继续执行System.err.println("优惠券扣减失败:" + e.getMessage());}}
}

结果说明:如果优惠券扣减失败(子事务回滚),订单创建操作(父事务)依然会正常提交;如果订单创建失败(父事务回滚),优惠券扣减操作(子事务)也会跟着回滚。

二、常见误区与实战建议

1. 同类方法内部调用,传播行为失效

Spring 事务基于动态代理实现,同类方法内部调用时,不会经过代理,导致 @Transactional 注解失效,传播行为自然不生效。

@Service
public class OrderService {// 错误示例:内部调用,传播行为失效@Transactional(rollbackFor = Exception.class)public void createOrder() {// 内部调用 deductStock,@Transactional 注解失效this.deductStock();}@Transactional(propagation = Propagation.REQUIRES_NEW)public void deductStock() {// ... 库存扣减逻辑}
}

解决方案:通过 Spring 上下文获取自身代理对象调用,或拆分方法到不同 Service 类。

2. 传播行为与隔离级别区分开

不少人会混淆“传播行为”和“隔离级别”:传播行为控制的是“事务之间的调用关系”,隔离级别控制的是“事务内部对数据的可见性”(如脏读、不可重复读),两者互不影响,可独立配置。

3. 优先使用默认传播行为,按需选型

日常开发中,REQUIRED(默认)能覆盖 80% 以上场景;需要独立事务用 REQUIRES_NEW;查询方法用 SUPPORTS;严格依赖/禁止事务用 MANDATORY/NEVER;嵌套事务谨慎使用(依赖数据库支持)。

三、总结

Spring 事务传播行为的本质是“事务边界的控制规则”,核心是解决“多方法调用时事务如何协同”的问题。掌握每种行为的适用场景,结合实际业务选择,才能避免事务漏洞(如数据不一致、事务失效、资源浪费)。

建议实际开发中,先明确“方法间事务是否需要协同”,再选择对应的传播行为,同时搭配 rollbackFor(指定回滚异常类型)、readOnly(查询优化)等属性,让事务控制更精准、高效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1173773.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

OSPF实验-HCIA-rj

任务要求如下&#xff1a;首先构建一个基础模型划分广播域&#xff1a;area0四个广播域&#xff08;骨干加三个环回&#xff09;&#xff0c;area1两个广播域&#xff08;只需配一个&#xff09;操作流程及知识点&#xff1a;一.R3同属区域0和1&#xff0c;应是ABRABR定义&…

手把手教你学Simulink--基础储能管理场景实例:基于Simulink的电池簇间一致性管理与均衡仿真

目录 手把手教你学Simulink 一、引言&#xff1a;为什么大型储能电站必须关注“簇间一致性”&#xff1f; 二、系统整体架构 控制层级&#xff1a; 三、关键一致性指标定义 四、Simulink 建模全流程 步骤1&#xff1a;差异化电池簇建模 步骤2&#xff1a;本地簇控制器&…

上饶市横峰弋阳余干鄱阳雅思培训辅导机构推荐,2026权威出国雅思课程中心学校口碑排行榜 - 苏木2025

基于全网调研与县域考生需求分析,结合权威教学评估体系,本次针对上饶市横峰、弋阳、余干、鄱阳、万年、婺源区域雅思培训市场,开展全面、深度测评,聚焦考生选课难题与考试痛点,从优质课程供给、高分提分技巧、性价…

抚州市崇仁乐安宜黄金溪资溪广昌雅思培训辅导机构推荐:2026权威出国雅思课程中心学校口碑排行榜 - 苏木2025

基于2026年雅思考试题型微调趋势及机考普及要求,结合抚州市崇仁、乐安、宜黄、金溪、资溪、广昌等区域考生核心需求,我们开展了为期一个月的全网权威调研与深度测评,聚焦雅思培训选课难题,从机构资质、师资力量、提…

抚州市崇仁乐安宜黄金溪资溪广昌雅思培训辅导机构推荐,2026权威出国雅思课程中心学校口碑排行榜 - 苏木2025

面对雅思备考中的提分瓶颈与机构选择困难,一份基于真实数据和多维测评的排行榜,成为抚州考生破解选课难题的关键。 备考雅思时,无论是自学过程中听力抓不住关键词、写作逻辑混乱的普遍困境,还是选择培训班时对师资…

机房U位资产管理传感器续航时间揭秘:超长待机让管理更轻松

机房U位资产管理传感器作为数据采集的核心终端&#xff0c;其续航稳定性直接决定管理体系的有效性。传统传感器因续航不足频繁停机&#xff0c;导致数据断层、维护繁琐&#xff0c;进一步加剧空间利用率低、资产跟踪难、合规记录残缺等痛点。据腾讯云开发者社区《机房U位资产管…

职场人的结构化思维

职场人的结构化思维 结构化思维职场人的结构化思维一. 什么是结构化思维1&#xff09;拆解2&#xff09;归纳3&#xff09;重构二. 结构化思维目的和作用三. 结构化思维沟通与表达1&#xff09;金字塔结构2&#xff09;PREP原则四. 结构化思维问题分析方法1&#xff09;5W2H分析…

2026年AI获客服务商技术流派深度解析:从综合服务到垂直深耕的五大企业全链路拆解 - 品牌推荐

当前,生成式人工智能正以前所未有的深度重塑商业信息的获取与分发逻辑。AI搜索优化(GEO)作为企业连接新一代流量入口的核心能力,已成为驱动业务增长的关键战略。为系统梳理行业前沿实践,精准识别具备技术创新与实…

感知机的对偶形式是怎么来的

感知机的对偶形式是怎么来的&#xff1a;1. 原始形式&#xff1a;老师亲自调整教案 想象你在教一个学生分类水果&#xff1a; 原始形式&#xff1a;你&#xff08;老师&#xff09;心中有一个“标准答案”&#xff08;权重向量 www&#xff09;看到学生把苹果误判为橘子&#x…

内核(Kernel)与操作系统(OS)

内核&#xff08;Kernel&#xff09;与操作系统&#xff08;OS&#xff09;的关系&#xff1a;核心不同但紧密相关 简单来说&#xff1a;内核是操作系统的核心&#xff0c;但操作系统不止包含内核。内核&#xff08;Kernel&#xff09; 定义&#xff1a;运行在内核态&#xff0…

盘点支付宝立减金回收变现权威合规平台 - 淘淘收小程序

你是不是也有过这样的经历?参与支付宝活动获得不少立减金,想用的时候却发现使用条件苛刻,或是有效期太短容易过期。这些立减金食之无味、弃之可惜,闲置在账户里最终只能浪费。 我有个朋友曾通过支付宝银行活动拿到…

ArrayOS AG高危命令注入漏洞(CVE-2025-66644)技术分析与修复指南

CVE-2025-66644: ArrayOS AG高危命令注入漏洞分析 &#x1f4cb; 项目描述 CVE-2025-66644是Array Networks的ArrayOS AG网络操作系统中发现的一个高危安全漏洞。该漏洞属于操作系统命令注入类型(CWE-78)&#xff0c;CVSS评分为7.2&#xff08;高危&#xff09;。受影响版本为…

系统性地深入分析一下Oracle EBS中 寄售(Consignment)库存 的管理和结算全流程

系统性地深入分析一下Oracle EBS中 寄售&#xff08;Consignment&#xff09;库存 的管理和结算全流程。寄售库存的本质是 “物料在买方处&#xff0c;但物权仍属于供应商&#xff0c;直到被消耗或使用后才发生买卖关系并结算”。一、核心概念与业务场景核心特点&#xff1a;物…

学霸同款2026 AI论文写作软件TOP9:MBA毕业论文全场景测评

学霸同款2026 AI论文写作软件TOP9&#xff1a;MBA毕业论文全场景测评 2026年MBA论文写作工具测评&#xff1a;精准适配学术场景的AI软件推荐 随着人工智能技术在学术领域的深度应用&#xff0c;越来越多的MBA学生开始借助AI论文写作工具提升研究效率。然而&#xff0c;面对市场…

2025年最新盘点:CTU货架公司哪家强?,组合式货架/货架定制/背网货架/悬臂货架/重型货架/中型货架/牛脚式货架CTU货架公司口碑推荐 - 品牌推荐师

随着智能制造与智慧物流的深度融合,仓储自动化已成为企业降本增效的核心战场。作为自动化仓储系统的关键物理载体,CTU(料箱搬运机器人)货架的重要性日益凸显。它不仅需要承载海量SKU的精准存储,更要与机器人、管理…

【大气】基于matlab模拟地球气候的Ghil-Sellers能量平衡模型【含Matlab源码 14973期】

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到海神之光博客之家&#x1f49e;&#x1f49e;&#x1f49e;&#x1f49…

从“百花齐放”到“强者恒强”:深度解析国产数据库“南达梦,北金仓”新格局

文章目录格局之变&#xff1a;三个阶段&#xff0c;三种形态第一阶段&#xff1a;“四朵金花”时代&#xff08;政策驱动&#xff0c;初步破局&#xff09;第二阶段&#xff1a;“百花齐放”时代&#xff08;资本涌入&#xff0c;百舸争流&#xff09;第三阶段&#xff1a;“强…

在SAP中,处理日常总账、应收、应付等外币业务时,系统默认使用汇率类型 M(平均汇率)

在SAP中&#xff0c;处理日常总账、应收、应付等外币业务时&#xff0c;系统默认使用汇率类型 M&#xff08;平均汇率&#xff09;。 这个默认值在系统配置中定义&#xff0c;以下是核心配置的路径和说明&#xff1a; 配置项事务码/路径作用与说明检查汇率类型OB07 或 IMG路径…

2025年国内可靠的防雨箱盖工厂联系电话,开关防雨箱/横臂监控杆/消防中心控制台/成品操作台公司排行 - 品牌推荐师

行业背景与趋势洞察 随着工业4.0与智慧城市建设的推进,防雨箱盖作为户外设备防护的核心部件,其市场需求呈现爆发式增长。从电力能源到交通监控,从通信基站到安防系统,防雨箱盖的性能直接关系到设备运行的稳定性与寿…

学霸同款10个AI论文平台,自考毕业论文轻松搞定!

学霸同款10个AI论文平台&#xff0c;自考毕业论文轻松搞定&#xff01; AI工具让论文写作不再难 在自考论文写作的道路上&#xff0c;许多学生常常面临时间紧张、资料匮乏、思路混乱等问题。而随着人工智能技术的发展&#xff0c;AI工具正逐步成为学术写作中的得力助手。这些工…