1. REQUIRED (必须的,默认):
如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是最常见的选择,大部分业务场景都适用。
2. SUPPORTS (支持的):
如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务方式执行。这种方法对于那些不需要事务也能正确执行,但在事务环境下运行也不会造成任何问题的方法特别有用。
3. MANDATORY (强制的):
必须在一个已存在的事务中执行,如果当前没有事务则抛出异常。
4. REQUIRES_NEW (需要新的):
总是创建一个新的事务,如果当前存在事务,则把当前事务挂起,新的事务结束后,再恢复之前被挂起的事务。
5. NOT_SUPPORTED (不支持):
不使用事务,如果当前存在事务,则将其挂起,直到该方法完成后再继续执行。
6. NEVER (绝不):
不允许在事务中执行,如果当前存在事务,则抛出异常。
7. NESTED (嵌套的):
如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则如同 `REQUIRED` 一样,新建一个事务。嵌套事务可以独立于父事务进行提交或回滚,而不会影响父事务的状态。
通过在Service层方法上使用 `@Transactional` 注解,并设置其 `propagation` 属性,可以指定事务的传播行为,以满足不同场景下的事务管理需求。例如:
@Transactional(propagation = Propagation.REQUIRED)
public void someMethodInService() {
// ...
}
这样就能够确保在调用该方法时,遵循指定的事务传播规则。
Spring事务的传播机制底层原理涉及到Spring AOP(面向切面编程)和事务管理器的协同工作。当我们在服务方法上标注了`@Transactional`注解后,Spring通过动态代理机制(基于JDK Proxy或CGLIB)创建一个代理对象,该代理对象在方法调用前后插入必要的事务处理逻辑。 具体实现步骤如下: 1. 事务代理: - 当客户端调用服务方法时,实际上是调用Spring生成的代理对象的方法。 - 代理对象在方法调用前首先会通过Spring的事务管理器(如DataSourceTransactionManager、JpaTransactionManager等实现)来检查是否存在当前线程绑定的事务上下文。 2. 事务决策: - 根据`@Transactional`注解声明的事务传播属性,代理对象决定如何处理事务: - 创建新的事务(如`REQUIRES_NEW`) - 加入现有事务(如`REQUIRED`、`SUPPORTS`、`MANDATORY`) - 挂起现有事务(如`REQUIRES_NEW`、`NOT_SUPPORTED`) - 抛出异常(如`NEVER`) 3. 事务同步: -Spring利用Transaction
Synchronization
Manager来管理和维护事务相关的线程绑定信息,如使用ThreadLocal来存储事务状态和同步回调。 - 在事务开始、提交、回滚等关键节点,会触发相应的事务同步监听器,执行相应的清理和同步操作。 4. 事务边界管理: - 当方法调用结束后,代理对象会判断是否有未捕获的异常,如果有,根据事务的配置(rollbackFor、noRollbackFor)来决定是否回滚事务;如果没有异常,则提交事务。 5. 事务传播的具体实现: - 事务传播的实际动作由事务管理器来执行,比如当需要创建新事务时,事务管理器会调用连接(如JDBC Connection或Hibernate Session)的相关API来启动和管理事务。 通过上述机制,Spring能够在方法调用的前后透明地处理事务的开始、结束、回滚以及传播行为,使得开发者能够更加关注业务逻辑的实现,而不是底层的事务管理细节。