Spring是如何传播事务的?
Spring框架通过声明式事务管理来传播事务,主要依赖于AOP(面向切面编程)和事务拦截器来实现。Spring的事务传播机制是基于Java Transaction API (JTA) 或者本地资源管理器(如Hibernate、JDBC等)来完成的。以下是Spring如何实现事务传播的基本过程:
1. 配置事务管理器
首先,你需要配置一个合适的事务管理器,这取决于你使用的数据访问技术。例如,如果你使用的是JDBC或MyBatis,你可以选择DataSourceTransactionManager
;如果使用的是Hibernate,则可以使用HibernateTransactionManager
;对于分布式事务,可以使用JtaTransactionManager
。
2. 使用@Transactional注解
在需要事务管理的方法或类上添加@Transactional
注解,并设置相应的传播行为属性(propagation)。这是最常用的声明式事务管理方式。例如:
@Transactional(propagation = Propagation.REQUIRED)
public void performService() {// 业务逻辑代码
}
3. AOP自动代理
当你配置了事务管理器并使用了@Transactional
注解后,Spring会自动创建代理对象。当调用被@Transactional
标注的方法时,实际上是通过这个代理对象进行调用。代理对象会在方法执行前后进行事务的开启、提交或回滚操作。
4. 事务传播行为的应用
根据不同的传播行为设置,Spring会决定当前方法是否应该在已有事务中运行,还是应该启动新事务,或者以其他方式处理事务。比如,Propagation.REQUIRED
表示如果当前存在事务,则加入该事务;如果没有事务,则创建一个新事务。
5. 异常处理
默认情况下,Spring会在遇到运行时异常或错误时回滚事务。不过,你可以通过@Transactional
注解的rollbackFor和noRollbackFor属性来自定义哪些异常发生时应回滚事务,哪些不应回滚。
通过这种方式,Spring能够灵活地管理和传播事务,确保业务逻辑的一致性和完整性。同时,它也提供了足够的灵活性,让开发者可以根据实际需求定制事务的行为。
Spring事务传播行为
Spring事务传播行为定义了在存在或不存在当前事务时,如何处理新方法的事务。以下是各个传播行为的具体说明及其典型应用场景:
-
REQUIRED(默认值)
- 描述: 如果当前存在事务,则加入该事务;如果不存在事务,则创建一个新事务。
- 应用场景: 大多数情况下,这是最常用的设置。例如,在服务层中执行数据库操作,通常希望这些操作在同一事务中进行,以确保数据一致性。
-
SUPPORTS
- 描述: 如果当前存在事务,则加入该事务;如果不存在事务,则以非事务方式继续运行。
- 应用场景: 适用于那些不需要事务性保障的操作,但如果被其他需要事务的操作调用时,可以共享外部事务。比如读取一些不敏感的数据信息。
-
MANDATORY
- 描述: 如果当前存在事务,则加入该事务;如果不存在事务,则抛出异常。
- 应用场景: 当你确定某些业务逻辑必须在事务内执行时使用。这可以作为一种安全措施,确保不会意外地以非事务方式调用关键操作。
-
REQUIRES_NEW
- 描述: 创建一个新的事务,如果当前存在事务,则暂停当前事务。
- 应用场景: 需要确保某个操作独立于其他事务,即使外围事务回滚也不受影响。例如,记录审计日志或发送通知消息,这些操作应独立于业务逻辑事务。
-
NOT_SUPPORTED
- 描述: 以非事务方式执行操作,如果当前存在事务,则暂停当前事务。
- 应用场景: 对于性能要求较高且不需要事务保证的操作,如查询操作,避免不必要的事务开销。
-
NEVER
- 描述: 以非事务方式执行,如果当前存在事务,则抛出异常。
- 应用场景: 确保某些方法绝对不会在事务上下文中被调用,适合那些明确不应该与事务关联的操作。
-
NESTED
- 描述: 如果当前存在事务,则在嵌套事务内执行。如果当前不存在事务,则其行为类似于
REQUIRED
。 - 应用场景: 当你需要支持部分回滚时使用。例如,如果你在一个大事务中有多个步骤,并且希望在某一步骤失败时仅回滚该步骤而不是整个事务。
- 描述: 如果当前存在事务,则在嵌套事务内执行。如果当前不存在事务,则其行为类似于
下面是一个简单的示例展示如何使用这些传播行为:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;@Service
public class TransactionalService {@Autowiredprivate AnotherTransactionalService anotherService;@Transactional(propagation = Propagation.REQUIRED)public void required() {// 业务逻辑anotherService.anotherMethod();}@Transactional(propagation = Propagation.REQUIRES_NEW)public void requiresNew() throws Exception {// 业务逻辑anotherService.anotherMethod();}// 其他传播行为的示例略...
}
在这个例子中,required()
方法使用了Propagation.REQUIRED
传播行为,意味着如果当前有事务,它会加入这个事务;如果没有,就会创建一个新事务。而requiresNew()
方法使用了Propagation.REQUIRES_NEW
,这会保证每次调用时都会有一个独立的新事务开始,即使在外围已经有事务存在。注意,具体到每个传播行为的实现细节都依赖于Spring框架底层的事务管理机制以及所使用的事务管理器(如JpaTransactionManager、DataSourceTransactionManager等)。