spring事务 connection

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生成代理类,织入通知。


注解事务的就会生成代理类,织入事务拦截器逻辑。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值