[db:标题]

摘要:Spring的事务传播机制 什么是Spring事务传播机制 Spring的事务传播机制,主要是用于控制多个事务方法相互调用时的事务行为。 在后端复杂的业务场景中,多个事务之间的调用可能会导致事务的不一致,例如:数据重复提交,数据丢失等问题,
Spring的事务传播机制 什么是Spring事务传播机制 Spring的事务传播机制,主要是用于控制多个事务方法相互调用时的事务行为。 在后端复杂的业务场景中,多个事务之间的调用可能会导致事务的不一致,例如:数据重复提交,数据丢失等问题,使用事务传播机制可以避免这些问题的发生,从而保证事务的一致性和数据的完整性。 Spring的事务规定了7种传播行为 Spring 通过 @Transactional 注解的 propagation 属性来设置传播级别 Propagation.REQUIRED (默认) 含义:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。 特点:这是最常用、且Spring默认的传播行为。适用于绝大多数业务场景。 回滚:内部方法抛出异常未被捕获,会导致整个事务(包括外部方法的操作)回滚。 Propagation.REQUIRES_NEW 含义:无论当前是否存在事务,都会创建一个新的事务,并将当前事务(如果存在)挂起。 特点:创建的是一个完全独立的事务,有自己的提交和回滚边界。 回滚:内部新事务回滚,不影响外部事务(如果外部事务正常提交)。 外部事务回滚,会将内部新事务也回滚(因为外部事务的回滚会恢复到调用 REQUIRES_NEW 方法之前的状态)。 场景:记录日志、发送通知、审计等需要独立提交的场景。 Propagation.NESTED 含义:如果当前存在事务,则在嵌套事务内执行(基于数据库的 Savepoint 机制);如果不存在事务,则创建一个新事务。 特点:不是创建一个真正的新事务,而是在当前事务中设置一个保存点(Savepoint)。它可以在不破坏外部事务的情况下进行部分回滚。 回滚:内部嵌套事务回滚,只回滚到保存点,不影响外部事务已做的其他操作。外部事务回滚,会回滚整个事务,包括嵌套事务的操作。与 REQUIRES_NEW 区别:NESTED 是“子事务”,依赖于外部事务;REQUIRES_NEW 是“独立事务”,与外部事务并列。 Propagation.SUPPORTS 含义:如果当前存在事务,则加入该事务;如果不存在事务,则以非事务方式执行。 特点:对事务是“可有可无”的态度。 场景:适用于只读操作或对事务不敏感的方法。 Propagation.NOT_SUPPORTED 含义:以非事务方式执行操作。如果当前存在事务,则将当前事务挂起。 特点:强制方法不运行在事务中,可以提高性能。 场景:执行一些耗时长、不需要事务保证的操作。 Propagation.NEVER 含义:以非事务方式执行,如果当前存在事务,则抛出异常。 特点:强制禁止在事务中执行此方法。 场景:某些特定操作明确要求不能在事务上下文中运行。 Propagation.MANDATORY 含义:方法必须在一个已存在的事务中执行,如果当前没有事务,则抛出异常。 特点:强制要求调用方必须提供一个事务。 场景:用于那些必须作为更大事务一部分才能保证一致性的操作 面试题 面试官问:一个长的事务方法a,在读写分离的情况下,里面既有读库操作,也有写库操作,再调用个读库方法b,方法b该用什么传播机制呢? 答:这种情况,读方法如果是最后一步,直接not_supported就行了,避免读报错导致数据回滚。如果是中间步骤,最好还是要required,因为异常失败需要回滚一下。 例如:A B C三个操作,C就是最后一步,B就是中间步骤如果一个读操作在中间(如B操作)失败了,那么就需要让A做回滚,因为C还没执行,所以A必须回滚才能保证一致性。 Spring事务失效可能是哪些原因 首先,容易造成事务失效的方式是通过@Transactional注解方式的声明式事务。 @Transactional是基于Spring的AOP来实现的,而AOP机制又是基于动态代理实现的,如果代理失效那么事务也就失效了。 Spring事务失效的场景 AOP代理失效 @Transactional应用在非public方法上 @Service public class UserService { @Transactional private void updateUserData() { // private方法 // ... } } 由于代理机制会为 public 方法创建拦截器,事务可以正常生效。而非public得方法,JDK代理是不会创建拦截器的,虽然CGLIB可能支持,但行为不一致,不保证生效。 因此在使用时还是强烈建议放到public方法上。
阅读全文