前言
本篇以@EnableTransactionManagement注解的方式来讲解Spring事务的实现
@EnableTransactionManagement配置
proxyTargetClass配置
在Spring中其事务是利用动态代理实现,动态代理有2种实现方式:
-
false:基于CGLIB来实现
-
true:基于Java原生的Proxy实现,这种方式原类必须要定义接口。
这个参数就是表示动态代理实现方式,如果值设置true,表示需要代理类都基于CGLIB来实现;默认情况下值是设置成false表示如果原类如果定义了接口则通过Proxy实现否则基于CGLIB来实现。
adviceMode配置
配置动态代理的织入方式
-
PROXY:JDK动态代理
-
ASPECTJ:AspectJ实现的代理
proxyTargetClass是配置PROXY的情况下才能生效
@Transactional配置
value事务管理类配置
根据value值获取Spring获取事务管理类PlatformTransactionManager,来进行事务管理。
propagation事务传播方式配置
Propagation.MANDATORY(强制性的事务)
当前必须存在一个事务,否则抛出异常,主要功能就是保证能加入到主事务,主事务不存在就会抛异常。
Propagation.REQUIRED(必填的事务)
如果当前已经存在事务,那么加入该事务,如果不存在事务,创建一个事务,这是默认的传播属性值。
Propagation.NEVER(从不)
当前事务不能合并到主事务,如果已经存在主事务则报错,这个跟MANDATORY相反。
Propagation.NOT_SUPPORTED(不支持事务)
以非事务方式执行操作,如果当前存在事务,就把当前事务挂起,挂起的原理就是将ThreadLocal缓存删掉,回到主事务后重新设置。
Propagation.REQUIRES_NEW(创建新事务)
处理从事务如果当前有主事务,将主事务挂起,创建新的事务作为当前事务,从事务处理完毕后,将主事务还原
Propagation.NESTED(嵌套事务)
利用savepoint创建主事务保存点,如果从事务异常,则可以从保存点开始继续执行主事务。
isolation事务隔离级别配置
DEFAULT:默认隔离级别
使用数据库设置的隔离级别
READ_UNCOMMITTED:读未提交隔离级别
使用读可提交隔离级别
READ_COMMITTED:读已提交隔离级别
使用读已提交隔离级别
REPEATABLE_READ:可重复读隔离级别
使用可重复读隔离级别
SERIALIZABLE:串行化隔离级别
使用串行化隔离级别
具体事务隔离级别细节可参考:https://my.oschina.net/u/945573/blog/2242185
timeout事务超时时间配置
事务超时时间设置timeout,其底层是通过Statement#setQueryTimeout()设置,一个事务可能有多个Statement,所以Spring通过累计每个Statement时间去计算事务超时时间,目前Spring事务集成MyBatis上设置这个参数是不生效。
readOnly事务是否只能查询不能修改配置
设置事务仅支持查询操作不支持修改操作。
rollbackFor && rollbackForClassName 需要回滚的异常类配置
根据抛出异常的对象的类或者类的名称来匹配,匹配上则回滚,例如设置 rollbackFor=IOError.class ,如果抛出的异常类是IOError或其子类则回滚
noRollbackFor && noRollbackForClassName 不需要回滚的异常类配置
跟上面的配置相反,根据抛出异常的对象的类或者类的名称来匹配,匹配上则不回滚
原理
事务大致原理是通过AOP创建代理对象将开启事务和提交事务(或回滚事务)织入到事务执行的核心代码执行前和执行后,AOP实现的原来跟我之前写的文章类似:https://my.oschina.net/u/945573/blog/3047657
我们带着问题来了解下他的实现
如何创建事务的代理对象
在Spring启动时会解析@EnableTransactionManagement注解并通过解析@Import将事务的配置类导入,配置类有2个分别是AutoProxyRegistrar和ProxyTransactionManagementConfiguration。AutoProxyRegistrar会将代理对象的创建组件InfrastructureAdvisorAutoProxyCreator注册进Spring容器。
看InfrastructureAdvisorAutoProxyCreator继承关系就能发现其实现了BeanPostProcessor类,Spring容器每个类在创建的时候会调用BeanPostProcessor里的postProcessBeforeInitialization方法,在初始化结束的时候会调用postProcessAfterInitialization方法。BeanPostProcessor作用就是修改这个创建的对象,InfrastructureAdvisorAutoProxyCreator就是利用了BeanPostProcessor将原来的类替换成代理类。
在创建代理过程中如何知道该类是否需要被替换成事务代理对象
上篇文章讲过AOP的组成有Advisor(切面),Pointcut(切点),Advice(增强),Advisor包含Pointcut和Advice。Pointcut表示切入的位置,在Spring中Pointcut接口是做一个匹配的功能包括Class和Method的匹配,只有匹配上才能做进一步增强。所以Spring查找容器中所有Advisor对象,然后取出Pointcut去匹配该类上是否注解了@Transactional,如果是则该类需要做代理。如果该类上没有注解则继续查找该类方法上是否注解了@Transactional,如果是则该类需要做代理。
Advisor是什么时候注册到Spring容器的
之前讲过导入的配置类有2个分别是AutoProxyRegistrar和ProxyTransactionManagementConfiguration,Advisor正是通过ProxyTransactionManagementConfiguration注册进去的。看下他的代码实现:
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
advisor.setOrder(this.enableTx.getNumber("order"));
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
这个类不仅注册了Advisor对象,还有TransactionAttributeSource和TransactionInterceptor。
-
TransactionAttributeSource类是@Transactional解析器,能根据Method或者Class对象将Method或者Class上的@Transactional配置的属性解析出来。
-
TransactionInterceptor就是Advice增强器,增强器作用就是会拦截事务方法的调用,在事务方法调用前开启事务调用后提交或者回滚事务。
如何对事务进行管理
不管是JPA还是JDBC,Spring都是通过PlatformTransactionManager类来管理事务,Spring通过@Transactional的value配置的bean名称查找Spring容器中的PlatformTransactionManager对象,默认情况下value值为空,会获取Spring容器中的PlatformTransactionManager类型的对象作为事务管理器。看下PlatformTransactionManager接口
public interface PlatformTransactionManager {
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
void commit(TransactionStatus status) throws TransactionException;
void rollback(TransactionStatus status) throws TransactionException;
}
getTransaction方法作用是开启事务,TransactionDefinition类型的参数为事务的配置,返回值是TransactionStatus类型事务的状态。commit和rollback分别对应事务的提交和回滚。