从@Transactional看事务的传播和隔离

本文深入探讨了Spring中的事务管理,包括transactionManager的选择、事务的传播行为(如REQUIRED、SUPPORTS、REQUIRES_NEW等)、隔离级别(如READ_COMMITTED、SERIALIZABLE等)以及timeout和readOnly属性的设定。同时,提到了事务失效的常见场景,如非public方法、嵌套事务和异常处理策略。

spring如何处理事务呢?下面是个伪代码示意:

	  begin Transactional;
       try{
   
   
           //TODO
           commit;
       }catch (Throwable e){
   
   
           if(e属于该提交的(即noRollbackFor指定)的异常类型){
   
   
               commit;
           }else {
   
   
               rollback;
           }
       }

1. transactionManager 当在配置文件中有多个TransactionManager,可以用该属性指定使用哪个事务管理器

如果要配置全局事务管理,参考这篇文章全局性事务控制如何在springboot中配置

2. 事务的传播行为(propagation) ,默认值为REQUIRED

  • Propagation.REQUIRED
    默认传播行为 如果有事务那么加入此事务,没有就新建一个事务
	/**
	 * Support a current transaction, create a new one if none exists.
	 * <p>This is the default setting of a transaction annotation.
	 */
  • Propagation.SUPPORTS
    如果其他bean调用这个方法,在其他bean中声明了事务那么久加入事务,如果其他bean中没有声明事务就不用事务
	/**
	 * Support a current transaction, execute non-transactionally if none exists.
	 * <p>Note: For transaction managers with transaction synchronization,
	 * PROPAGATION_SUPPORTS is slightly different from no transaction at all,
	 * as it defines a transaction scope that synchronization will apply for.
	 * As a consequence, the same resources (JDBC Connection, Hibernate Session, etc)
	 * will be shared for the entire specified scope. Note that this depends on
	 * the actual synchronization configuration of the transaction manager.
	 */
  • Propagation.REQUIRES_NEW
    不管是否存在事务,都创
<think>我们正在讨论Spring框架中的@Transactional注解的事务传播机制。事务传播机制定义了在多个事务方法相互调用时,事务应该如何传播。Spring提供了7种传播行为,定义在Propagation枚举中。 1. **PROPAGATION_REQUIRED(默认)**:如果当前存在事务,则加入事务;如果当前没有事务,则创建一个新的事务。 2. **PROPAGATION_SUPPORTS**:如果当前存在事务,则加入事务;如果当前没有事务,则以非事务的方式继续运行。 3. **PROPAGATION_MANDATORY**:如果当前存在事务,则加入事务;如果当前没有事务,则抛出异常。 4. **PROPAGATION_REQUIRES_NEW**:创建一个新的事务,如果当前存在事务,则把当前事务挂起。 5. **PROPAGATION_NOT_SUPPORTED**:以非事务方式运行,如果当前存在事务,则把当前事务挂起。 6. **PROPAGATION_NEVER**:以非事务方式运行,如果当前存在事务,则抛出异常。 7. **PROPAGATION_NESTED**:如果当前存在事务,则创建一个事务作为当前事务嵌套事务来运行;如果当前没有事务,则该取值等价于PROPAGATION_REQUIRED。 下面通过代码示例来说明其中几种常用的传播机制: ### 示例1:PROPAGATION_REQUIRED ```java @Service public class UserService { @Autowired private UserRepository userRepository; @Transactional(propagation = Propagation.REQUIRED) public void createUser(User user) { userRepository.save(user); } } ``` 如果调用`createUser`方法时已经存在事务,则该方法会加入事务;如果没有事务,则创建一个新的事务。 ### 示例2:PROPAGATION_REQUIRES_NEW ```java @Service public class AccountService { @Autowired private AccountRepository accountRepository; @Transactional(propagation = Propagation.REQUIRES_NEW) public void updateAccount(Account account) { accountRepository.save(account); } } ``` 无论当前是否存在事务,`updateAccount`方法都会创建一个新的事务。如果当前存在事务,则将该事务挂起。 ### 示例3:PROPAGATION_NESTED ```java @Service public class OrderService { @Autowired private OrderRepository orderRepository; @Transactional(propagation = Propagation.NESTED) public void createOrder(Order order) { orderRepository.save(order); } } ``` 如果当前存在事务,则`createOrder`方法会创建一个嵌套事务嵌套事务是外部事务的子事务,在外部事务回滚时,嵌套事务也会回滚;而嵌套事务可以独立于外部事务进行回滚(通过保存点实现)。 ### 注意事项: - 事务传播行为是在方法调用时确定的。 - 使用`PROPAGATION_REQUIRES_NEW`时,会创建新的事务,同时挂起当前事务(如果存在),这意味着新事务事务是独立的,新事务的回滚会影响原事务,但原事务的回滚会影响新事务(因为新事务已经提交)吗?注意:新事务已经独立提交,原事务回滚会影响新事务,因为新事务已经提交了。但是,如果新事务抛出了异常,且没有被捕获,则会导致原事务也被标记为回滚(除非原事务捕获了异常并处理)。 - `PROPAGATION_NESTED`使用保存点(Savepoint)来实现,因此只适用于具有保存点功能的事务管理器(如JDBC的DataSourceTransactionManager),而适用于JTA(全局事务)。 ### 为什么需要传播机制? 在复杂的业务场景中,多个事务方法相互调用,需要明确事务的边界传播规则,以保证数据的一致性完整性。同的传播行为提供了灵活的事务控制方式。 ### 总结: 事务传播机制是Spring事务管理中的重要概念,通过合理设置传播行为,可以有效地控制事务的边界多个事务之间的影响。 §§相关问题§§: 1. Spring事务隔离级别有哪些? 2. 在Spring中,@Transactional注解在什么情况下会失效? 3. 如何配置Spring事务的超时时间? 4. 事务的嵌套挂起分别是什么意思? </think>### Java @Transactional事务传播机制 在Spring框架中,`@Transactional`的事务传播机制定义了**多个事务方法相互调用时**事务如何传递。Spring提供了7种传播行为(定义在`Propagation`枚举中): ```java public enum Propagation { REQUIRED, // 默认值:存在事务加入,否则新建 SUPPORTS, // 存在事务加入,否则非事务运行 MANDATORY, // 存在事务加入,否则抛异常 REQUIRES_NEW, // 新建事务,挂起当前事务(存在时) NOT_SUPPORTED, // 非事务运行,挂起当前事务(存在时) NEVER, // 非事务运行,存在事务则抛异常 NESTED // 嵌套事务(基于保存点) } ``` #### 核心机制详解(附代码示例) ##### 1. **REQUIRED(默认)** - **行为**:当前存在事务加入,否则创建新事务 - **场景**:嵌套调用需原子性操作 - **代码**: ```java @Transactional(propagation = Propagation.REQUIRED) public void methodA() { // 事务T1 methodB(); // 加入T1 } @Transactional(propagation = Propagation.REQUIRED) public void methodB() { // 加入已有事务T1 } ``` ##### 2. **REQUIRES_NEW** - **行为**:始终创建新事务,挂起当前事务(若有) - **场景**:独立操作需提交(如日志记录) - **代码**: ```java @Transactional(propagation = Propagation.REQUIRED) public void orderProcess() { // 事务T1 logService.auditLog(); // 新启事务T2 // T1异常影响T2提交 } @Service public class LogService { @Transactional(propagation = Propagation.REQUIRES_NEW) public void auditLog() { // 独立事务T2 } } ``` ##### 3. **NESTED** - **行为**:在已有事务中创建嵌套事务(基于保存点) - **特性**:外层事务回滚时嵌套事务必回滚,嵌套事务可单独回滚 - **代码**: ```java @Transactional public void purchase() { try { inventoryService.deductStock(); // 嵌套事务 } catch (Exception e) { // 仅回滚库存操作 } // 主事务继续 } @Service public class InventoryService { @Transactional(propagation = Propagation.NESTED) public void deductStock() { // 嵌套事务(Savepoint) } } ``` ##### 4. **MANDATORY** - **行为**:强制要求存在事务,否则抛`IllegalTransactionStateException` - **场景**:确保方法在事务中被调用 ```java @Transactional(propagation = Propagation.MANDATORY) public void refund() { // 必须在事务中调用 } ``` #### ⚠️ 关键注意事项 1. **事务挂起**:`REQUIRES_NEW`/`NOT_SUPPORTED`会挂起原事务,使用独立的数据库连接 2. **嵌套事务限制**:`NESTED`需要JDBC 3.0+驱动(如MySQL的InnoDB引擎) 3. **生效条件**:调用必须通过代理对象(同类内调用失效,需使用`AopContext.currentProxy()`) #### 传播行为选择建议 | 传播行为 | 适用场景 | |----------------|----------------------------------| | REQUIRED | 大多数业务逻辑(默认选择) | | REQUIRES_NEW | 独立操作(审计日志、消息发送) | | NESTED | 可部分回滚的子操作(库存扣减) | | MANDATORY | 强制事务上下文(支付核心操作) |
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值