spring事务使用了aop、动态代理,而数据库的事务最终是作用在connection上面的,那么spring整个过程中开头的begin,结束的commit,rollback如何保证使用的是同一个connection,以及mybatis如何拿到这条connection执行sql,还有再加上spring事务的传播特性的时候connection变化呢
一、spring事务从开启到结束使用同一条connection
1、TransactionInterceptor.invoke -> TransactionAspectSupport.invokeWithinTransaction 方法中的
createTransactionIfNecessary方法
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
status = tm.getTransaction(txAttr);
}
2、AbstractPlatformTransactionManager 的 TransactionStatus getTransaction(TransactionDefinition definition)
DataSourceTransactionManager 的 doGetTransaction()
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
ConnectionHolder conHolder =
(ConnectionHolder) TransactionSynchronizationManager.getResource(this.dataSource);
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
此时ConnectionHolder可能是null,比如新的线程时候,TransationSynchronizationManager就是关键,使用了ThreadLocal保存ConnectionHolder,
也就是说在一个线程执行过程中,你可以随时拿到保存的connection,这也就是整个过程的关键。
3、回到AbstractPlatformTransactionManager 的getTransaction
doBegin(transaction, definition);
DataSourceTransactionManager 的doBegin片段
if (txObject.getConnectionHolder() == null ||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
Connection newCon = this.dataSource.getConnection();
if (logger.isDebugEnabled()) {
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
}
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
//如果当前connectionHolder是null,从数据源取出一条connection生成一个ConnectionHolder设置到DataSourceTransactionObject
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// Switch to manual commit if necessary. This is very expensive in some JDBC drivers,
// so we don't want to do it unnecessarily (for example if we've explicitly
// configured the connection pool to set it already).
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
if (logger.isDebugEnabled()) {
logger.debug("Switching JDBC Connection [" + con + "] to manual commit");
}
con.setAutoCommit(false);
}
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// Bind the session holder to the thread.新的就绑定线程,供后面使用
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
}
4、以提交为例,TransactionAspectSupport中
正常提交事务commitTransactionAfterReturning(TransactionInfo txInfo)
最后到了DataSourceTransactionManager的doCommit(DefaultTransactionStatus status)
Connection con = txObject.getConnectionHolder().getConnection();
从status中拿到当前的connection,执行commit
5、mybatis
SpringManagedTransaction的openConnection
this.connection = DataSourceUtils.getConnection(this.dataSource);
DataSourceUtils
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
if (conHolder != null && (conHolder.hasConnection() || conHolder.isSynchronizedWithTransaction())) {
conHolder.requested();
if (!conHolder.hasConnection()) {
logger.debug("Fetching resumed JDBC Connection from DataSource");
conHolder.setConnection(dataSource.getConnection());
}
return conHolder.getConnection();
}
也是从上面保存的地方,根据线程拿到connection
二、spring事务的传播特性
TransactionDefinition中定义了事务的传播特性PROPAGATION_REQUIRED 支持当前事务,如果当前没有新建一个新的
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有无事务执行
PROPAGATION_MANDATORY 支持当前事务,如果当前没有抛出异常
PROPAGATION_REQUIRES_NEW 新建新的事务,当前有则挂起当前的事务
PROPAGATION_NOT_SUPPORTED 不支持当前事务,无事务执行
PROPAGATION_NEVER 不支持当前事务,当前有事务则抛出异常
PROPAGATION_NESTED 嵌套事务,类似PROPAGATION_REQUIRED
从AbstractPlatformTransactionManager 的getTransaction方法中的
if (isExistingTransaction(transaction)) {
// Existing transaction found -> check propagation behavior to find out how to behave.
return handleExistingTransaction(definition, transaction, debugEnabled);
}
可以分析到当前存在事务的情况,后面的就是当前不存在事务的处理。
下面看下PROPAGATION_REQUIRES_NEW 处理过程
handleExistingTransaction中
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
if (debugEnabled) {
logger.debug("Suspending current transaction, creating new transaction with name [" +
definition.getName() + "]");
}
SuspendedResourcesHolder suspendedResources = suspend(transaction);
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
doBegin(transaction, definition);
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException beginEx) {
resumeAfterBeginException(transaction, suspendedResources, beginEx);
throw beginEx;
}
catch (Error beginErr) {
resumeAfterBeginException(transaction, suspendedResources, beginErr);
throw beginErr;
}
}
suspend最终调用了DataSourceTransactionManager的doSuspend
过程就是当前线程解绑上一个事务的connectionHoder,当前的DataSourceTransactionObject的connectionHolder设置为null
回到上面 会给当前的事务新建一个DefaultTransactionStatus,并且这个status会引用上一个事务的SuspendedResourcesHolder(主要就是connection)
作用呢就是当前事物结束的时候,再拿出来恢复上一个事物。
AbstractPlatformTransactionManager的cleanupAfterCompletion
三、事务与aop
看spring事物时候,知道了事务拦截器TransactionInterceptor环绕通知处理了事务,也就是拦截有@Transactional的bean的方法
虽然都知道是使用了aop进一步是用了动态代理,那么源头是从哪开始的
建了一个工程,添加事务注解,启动容器,如下打印的日志:
[localhost-startStop-1] [DEBUG] DefaultListableBeanFactory: Returning cached instance of singleton bean 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0'
[localhost-startStop-1] [DEBUG] DefaultListableBeanFactory: Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
[localhost-startStop-1] [DEBUG] DefaultListableBeanFactory: Returning cached instance of singleton bean 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0'
[localhost-startStop-1] [DEBUG] AutowiredAnnotationBeanPostProcessor: Autowiring by type from bean name 'tradeServiceImpl' to bean named 'goodsDao'
[localhost-startStop-1] [DEBUG] InjectionMetadata: Processing injected method of bean 'tradeServiceImpl': AutowiredFieldElement for com.yi.trade.dao.TradeDao com.yi.trade.service.impl.TradeServiceImpl.tradeDao
[localhost-startStop-1] [DEBUG] DefaultListableBeanFactory: Returning cached instance of singleton bean 'tradeDao'
[localhost-startStop-1] [DEBUG] DefaultListableBeanFactory: Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
[localhost-startStop-1] [DEBUG] DefaultListableBeanFactory: Returning cached instance of singleton bean 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0'
[localhost-startStop-1] [DEBUG] DefaultListableBeanFactory: Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
[localhost-startStop-1] [DEBUG] DefaultListableBeanFactory: Returning cached instance of singleton bean 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0'
[localhost-startStop-1] [DEBUG] AutowiredAnnotationBeanPostProcessor: Autowiring by type from bean name 'tradeServiceImpl' to bean named 'tradeDao'
[localhost-startStop-1] [DEBUG] DefaultListableBeanFactory: Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
[localhost-startStop-1] [DEBUG] DefaultListableBeanFactory: Returning cached instance of singleton bean 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0'
[localhost-startStop-1] [DEBUG] DefaultListableBeanFactory: Returning cached instance of singleton bean 'org.springframework.transaction.config.internalTransactionAdvisor'
[localhost-startStop-1] [DEBUG] DefaultListableBeanFactory: Returning cached instance of singleton bean 'org.springframework.aop.aspectj.AspectJPointcutAdvisor#0'
[localhost-startStop-1] [DEBUG] AnnotationTransactionAttributeSource: Adding transactional method 'byTrade' with attribute: PROPAGATION_REQUIRED,ISOLATION_DEFAULT; ''
[localhost-startStop-1] [DEBUG] DefaultListableBeanFactory: Returning cached instance of singleton bean 'org.springframework.transaction.interceptor.TransactionInterceptor#0'
[localhost-startStop-1] [DEBUG] AnnotationAwareAspectJAutoProxyCreator: Creating implicit proxy for bean 'tradeServiceImpl' with 0 common interceptors and 1 specific interceptors
[localhost-startStop-1] [DEBUG] JdkDynamicAopProxy: Creating JDK dynamic proxy: target source is SingletonTargetSource for target object [com.yi.trade.service.impl.TradeServiceImpl@1a1cd3f]
[localhost-startStop-1] [DEBUG] DefaultListableBeanFactory: Finished creating instance of bean 'tradeServiceImpl'
可以看到AnnotationAwareAspectJAutoProxyCreator: Creating implicit proxy for bean 'tradeServiceImpl'以及后面的JdkDynamicAopProxy
明显就是生成代理类的日志
可是还是看不出在哪一步生成的,肯定是在createBean过程中,因为有Creating instance of bean 'tradeServiceImpl'~Finished creating instance of bean 'tradeServiceImpl'
那么继续跟踪代码发现是在
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(String, Object, RootBeanDefinition)的applyBeanPostProcessorsAfterInitialization
方法中,是一个beanProcessor.postProcessAfterInitialization方法生成代理类的,这个类就是AnnotationAwareAspectJAutoProxyCreator
以及知道在spring容器refresh时候会把容器中的beanProcessor注册到一个list中(registerBeanPostProcessors(beanFactory))
看了一下这个地方及其周边代码发现没有显式注入的,断点发现会有一个org.springframework.aop.config.internalAutoProxyCreator的bean
然后想到aop的一些标签处理
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
在AspectJAutoProxyBeanDefinitionParser中可以跟踪到注册
org.springframework.aop.config.AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry, Object)
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, Object source) {
return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
然后去掉配置中所有aop相关的,打印日志发现AnnotationAwareAspectJAutoProxyCreator变成了InfrastructureAdvisorAutoProxyCreator
AbstractAutoProxyCreator
AbstractAdvisorAutoProxyCreator
DefaultAdvisorAutoProxyCreator
InfrastructureAdvisorAutoProxyCreator
AspectJAwareAdvisorAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator
搜寻代码在<tx:annotation-driven/>的解析类AnnotationDrivenBeanDefinitionParser 的proxy模式中发现
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);
AbstractAutoProxyCreator的postProcessAfterInitialization会根据是否需要,返回bean的包装类,也就是根据
bean是否有advice生成代理类,织入通知。
注解事务的就会生成代理类,织入事务拦截器逻辑。