杭州网站排名seo,wordpress4.7.2 xss,天元建设集团有限公司青岛分公司,开发手游一、事务传播行为的基本概念
事务传播行为是Spring 框架中事务管理的核心概念#xff0c;用于定义当一个事务方法被另一个事务方法调用时#xff0c;事务应如何传播。通俗地说#xff0c;它解决了 “多个事务方法嵌套调用时#xff0c;新方法是加入现有事务还是创建新事务…一、事务传播行为的基本概念
事务传播行为是Spring 框架中事务管理的核心概念用于定义当一个事务方法被另一个事务方法调用时事务应如何传播。通俗地说它解决了 “多个事务方法嵌套调用时新方法是加入现有事务还是创建新事务” 的问题。
事务传播行为详解
在 Spring 中事务传播行为通过Transactional注解的propagation属性设置或在TransactionDefinition接口中定义。
二、Spring 事务传播行为的类型及详解
Spring 定义了 7 种事务传播行为以下是详细说明
传播行为类型英文名称核心定义典型应用场景 PROPAGATION_REQUIRED propagation_required REQUIRED默认若当前存在事务则加入该事务若不存在则创建新事务。核心业务逻辑如订单创建、支付流程确保操作在统一事务中。 PROPAGATION_REQUIRES_NEW (propagation_requires_new) REQUIRES_NEW无论当前是否存在事务都创建新事务原事务会被挂起。异步任务、日志记录不希望主事务失败影响子任务或需要独立回滚的操作。 PROPAGATION_NESTED (propagation_nested) NESTED若当前存在事务则创建嵌套事务通过数据库 Savepoint 实现若不存在则创建新事务。MySQL 等支持 Savepoint 的数据库中需要部分回滚的场景如订单部分退款。 PROPAGATION_SUPPORTS (propagation_supports) SUPPORTS若当前存在事务则加入事务若不存在则以非事务方式执行。只读查询方法可复用外层事务也可独立执行。 PROPAGATION_NOT_SUPPORTED (propagation_not_supported) NOT_SUPPORTED以非事务方式执行若当前存在事务则挂起该事务。明确不需要事务的操作如缓存更新避免事务开销。 PROPAGATION_NEVER (propagation_never) NEVER强制以非事务方式执行若当前存在事务则抛出异常。确保方法绝对不运行在事务中如只读缓存服务。 PROPAGATION_MANDATORY (propagation_mandatory) MANDATORY强制要求当前存在事务否则抛出异常。子方法必须依赖外层事务如财务系统中的分账操作。 三、Transactional注解的propagation属性的生效条件和触发时机
Spring事务传播行为Transactional注解的propagation属性的生效条件和触发时机需要结合以下几点来理解
1. 注解何时起作用
Spring事务传播行为的注解如Transactional(propagation Propagation.REQUIRED)会在以下场景中生效
方法被调用时当一个事务方法带有Transactional注解被另一个方法调用时事务传播行为会根据当前事务上下文动态决定如何处理事务。代理机制触发Spring通过动态代理JDK动态代理或CGLIB代理管理事务。只有当方法是通过代理对象调用时事务传播行为才会生效。
2.事务传播行为的触发流程
事务传播行为的触发流程可以简化为以下步骤
方法调用时检查事务上下文Spring会检查当前是否存在事务例如调用方是否已经开启事务。 根据传播行为决定事务处理方式
新建事务如REQUIRES_NEW挂起当前事务如果有开启新事务。加入事务如REQUIRED直接使用当前事务。强制要求/禁止事务如MANDATORY/NEVER根据规则抛出异常或挂起事务。
执行方法逻辑在确定事务上下文后执行方法体内的业务逻辑。 事务提交或回滚根据方法执行结果和传播行为规则提交或回滚事务。
3.示例代码
REQUIRED 传播行为的核心原则 “如果存在事务则加入不存在则创建新事务” 是针对每个被调用的方法而言的。具体逻辑如下
⑴. 核心判断时机
当一个被 Transactional(propagation Propagation.REQUIRED) 注解的方法被调用时Spring 会检查当前调用环境是否存在活跃事务
如果存在事务方法会加入该事务共享同一事务上下文。如果不存在事务方法会创建一个新事务。
⑵. 示例说明
场景一调用链中已有事务
Transactional(propagation Propagation.REQUIRED)
public void methodA() {// 事务已创建methodB(); // 调用 methodB
}Transactional(propagation Propagation.REQUIRED)
public void methodB() {// methodB 加入 methodA 的事务
}
分析methodB 被调用时由于调用链中已存在 methodA 创建的事务methodB 直接加入该事务两者共享同一事务边界。
场景二调用链中无事务
public void methodA() {// 无事务methodB(); // 调用 methodB
}Transactional(propagation Propagation.REQUIRED)
public void methodB() {// methodB 创建新事务
}
分析methodB 被调用时由于调用链中不存在事务methodB 会创建一个新事务。
⑶. 关键点
与方法层级无关无论方法是被直接调用还是嵌套在多层调用链中判断逻辑始终是当前调用环境是否存在事务。事务上下文由 Spring 维护Spring 通过 TransactionSynchronizationManager 管理事务上下文确保同一线程中共享事务状态。自调用问题若方法在同一个类中被自调用如 this.methodB()Transactional 注解会失效因为 Spring 的 AOP 代理机制只拦截外部调用。 在同一事务中 的含义 四、核心传播行为的典型场景与示例
1.propagation_required默认行为
这是最常用的传播行为。如果当前存在事务则加入该事务如果不存在则创建一个新事务。
应用场景核心业务逻辑确保多个操作在同一事务中。
示例创建订单并扣减库存
Service
public class OrderService {Autowiredprivate OrderRepository orderRepository;Autowiredprivate InventoryService inventoryService;Transactional(propagation Propagation.REQUIRED)public Order createOrder(Order order) {// 保存订单Order savedOrder orderRepository.save(order);// 扣减库存 (假设该方法也使用 REQUIRED 传播行为)inventoryService.reduceStock(order.getProductId(), order.getQuantity());return savedOrder;}
}
在这个例子中如果 createOrder 方法被一个事务调用reduceStock 方法会加入这个事务如果没有事务这两个操作会在一个新事务中执行。
2.propagation_requires_new
无论当前是否存在事务都创建一个新事务原事务会被挂起。
应用场景异步任务、日志记录不希望主事务失败影响子任务。
示例订单支付与日志记录
Service
public class PaymentService {Autowiredprivate LogService logService;Transactional(propagation Propagation.REQUIRED)public void processPayment(Payment payment) {// 处理支付try {// 支付逻辑...// 记录支付日志 (使用 REQUIRES_NEW 确保即使主事务回滚日志也会记录)logService.recordPaymentLog(payment);// 可能抛出异常的操作if (payment.getAmount() 10000) {throw new PaymentException(金额过大需要审核);}} catch (Exception e) {// 异常处理}}
}Service
public class LogService {Transactional(propagation Propagation.REQUIRES_NEW)public void recordPaymentLog(Payment payment) {// 记录日志逻辑}
}
在这个例子中即使 processPayment 方法因异常回滚recordPaymentLog 方法创建的日志记录也会被持久化因为它在独立的事务中执行。
3.propagation_nested
如果当前存在事务则创建一个嵌套事务通过数据库 Savepoint 实现如果不存在则创建一个新事务。
应用场景需要部分回滚的场景如订单部分退款。
示例订单部分退款
Service
public class RefundService {Autowiredprivate OrderRepository orderRepository;Autowiredprivate PaymentRepository paymentRepository;Transactional(propagation Propagation.REQUIRED)public void processPartialRefund(Long orderId, BigDecimal refundAmount) {Order order orderRepository.findById(orderId).orElseThrow();// 创建嵌套事务处理退款try {refundPayment(order.getPaymentId(), refundAmount);// 更新订单状态order.setStatus(OrderStatus.PARTIALLY_REFUNDED);orderRepository.save(order);} catch (RefundException e) {// 退款失败但订单状态更新不会受影响// 嵌套事务的回滚不会影响外层事务order.setStatus(OrderStatus.REFUND_FAILED);orderRepository.save(order);}}Transactional(propagation Propagation.NESTED)public void refundPayment(Long paymentId, BigDecimal amount) {// 退款逻辑if (amount 1000) {throw new RefundException(退款金额超过限制);}// 执行退款...}
}
在这个例子中如果 refundPayment 方法抛出异常只会回滚嵌套事务中的操作而外层事务中的订单状态更新仍然会提交。
4.propagation_supports
如果当前存在事务则加入事务如果不存在则以非事务方式执行。
应用场景只读查询方法可以复用外层事务也可以独立执行。
示例查询订单详情
Service
public class OrderQueryService {Autowiredprivate OrderRepository orderRepository;Transactional(propagation Propagation.SUPPORTS, readOnly true)public Order getOrderDetails(Long orderId) {// 查询订单详情return orderRepository.findById(orderId).orElseThrow();}
}
在这个例子中如果 getOrderDetails 方法在事务中被调用它会加入该事务如果不在事务中它会以非事务方式执行。这对于只读操作很有用可以减少事务开销。
5.propagation_not_supported
以非事务方式执行如果当前存在事务则挂起该事务。
应用场景明确不需要事务的操作如缓存更新。
示例更新缓存
Service
public class CacheService {Transactional(propagation Propagation.NOT_SUPPORTED)public void updateCache(String key, Object value) {// 更新缓存逻辑// 这里不需要事务因为缓存操作通常不需要回滚}
}
在这个例子中如果 updateCache 方法在事务中被调用当前事务会被挂起方法执行完毕后再恢复。
6.propagation_never
强制以非事务方式执行如果当前存在事务则抛出异常。
应用场景确保方法绝对不运行在事务中如只读缓存服务。
示例从缓存获取数据
Service
public class CacheQueryService {Transactional(propagation Propagation.NEVER)public Object getFromCache(String key) {// 从缓存获取数据// 确保此方法不会在事务中执行return cache.get(key);}
}
在这个例子中如果 getFromCache 方法在事务中被调用会抛出异常确保缓存操作不会在事务上下文中执行。
7.propagation_mandatory
强制要求当前存在事务否则抛出异常。
应用场景子方法必须依赖外层事务如财务系统中的分账操作。
示例财务分账
Service
public class AccountingService {Transactional(propagation Propagation.MANDATORY)public void distributeFunds(Payment payment) {// 分账逻辑// 必须在事务中执行确保数据一致性}
}Service
public class PaymentProcessingService {Autowiredprivate AccountingService accountingService;Transactional(propagation Propagation.REQUIRED)public void processPayment(Payment payment) {// 处理支付// ...// 分账 (依赖外层事务)accountingService.distributeFunds(payment);}
}
在这个例子中distributeFunds 方法必须在事务中调用否则会抛出异常。这确保了分账操作不会在没有事务保护的情况下执行。
五、事务传播行为的底层实现原理 数据库事务与 Spring 事务的映射 Spring 通过PlatformTransactionManager抽象层管理事务不同数据库如 MySQL、Oracle的事务机制会影响传播行为的实现。例如PROPAGATION_NESTED依赖数据库的SAVEPOINT机制MySQL InnoDB 引擎支持而 MyISAM 不支持。 事务挂起与恢复 当使用REQUIRES_NEW或NESTED时Spring 会将当前事务状态如连接、隔离级别保存到TransactionStatus对象中新事务完成后恢复原事务。
六、实战最佳实践与注意事项 优先使用默认传播行为REQUIRED 核心业务逻辑通常需要事务一致性默认值可避免遗漏配置。 REQUIRES_NEW 的性能开销 新事务会导致数据库连接切换和事务日志开销非必要场景避免滥用。 NESTED 的数据库兼容性 若系统需跨数据库部署谨慎使用NESTED可考虑用REQUIRES_NEW替代。 事务边界控制 避免在循环中调用REQUIRES_NEW方法如批量插入可通过Transactional包裹整个循环以减少事务开销。 异常处理与事务回滚 传播行为会影响异常传播例如REQUIRES_NEW的子事务异常不会影响外层事务需显式处理异常或配置rollbackFor。
七、总结
事务传播行为是 Spring 事务管理的核心机制合理选择传播行为可解决以下问题
多个服务方法间的事务边界划分核心业务与辅助操作的事务隔离复杂业务流程中的部分回滚需求