spring事务深入剖析 - 事务框架

本文以申明式事务为例,开始下探,分析spring事务的源码结构,再以mybatis为例,分析spring事务是如何作用于ORM的。

首先看看spring的配置文件,简而言之,TransactionAttributeSourceAdvisor采用AOP方式,将事务transactionInterceptor织入注解的特定的方法上

<bean class="org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor">
        <property name="transactionInterceptor"><ref bean="transactionInterceptor"/></property>
    </bean>
     
	<bean id="transactionInterceptor" class="com.CustomerTransactionInterceptor">
		<constructor-arg name="ptm" ref="shardingTransactionManager"></constructor-arg>
		<constructor-arg name="tas" ref="transactionAttributeSource"></constructor-arg>
	</bean>

    <bean id="customerSpringTransactionAnnotationParser" class="com.CustomerSpringTransactionAnnotationParser">
        <constructor-arg name="transactionManagerSpringBeanId">
            <value>shardingTransactionManager</value>
        </constructor-arg>
    </bean>
	
	<bean id="transactionAttributeSource" class="org.springframework.transaction.annotation.AnnotationTransactionAttributeSource">
        <constructor-arg name="annotationParser" ref="customerSpringTransactionAnnotationParser"></constructor-arg>
	</bean>

 那实际上,transactionInterceptor是实际调用shardingTransactionManager入口,它的父类TransactionAspectSupport封装了操作事务的具体代码

 

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {

 最终,在这个类里,我们找到了核心的事务操作代码,很清晰的,几步

  1. 从属性中获取事务属性配置,从BeanFactory中去除TransactionManager

  2. 开启事务,createTransactionIfNecessary

  3. 执行业务方法

  4. 遇错回滚,completeTransactionAfterThrowing方法判断,该Exception类型是否回滚,不回滚执行提交

  5. 清理事务信息,cleanupTransactionInfo将当前TransactionInfo设置为old

  6. 提交,commitTransactionAfterReturning执行提交

protected Object invokeWithinTransaction(Method method, Class targetClass, final InvocationCallback invocation)

 

final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		final String joinpointIdentification = methodIdentification(method, targetClass);

		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
			Object retVal = null;
			try {
				// This is an around advice: Invoke the next interceptor in the chain.
				// This will normally result in a target object being invoked.
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				// target invocation exception
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				cleanupTransactionInfo(txInfo);
			}
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

 

 事务的外围展现就是这么简单,内部的处理的复杂性主要有以下几点

1. 由于拦截事务是嵌套的,所以产生了以上6步执行的嵌套问题,这就产生了事务的传播特性

2. 底层数据库的不同,数据库驱动程序不同,产生了事务的兼容性问题

3. ORM框架百花齐放,如何能和spring事务无缝整合,也是一个棘手的问题

 

接下来我们先以JDBC事务为例进行说明

 先看xml文件的配置,可以知道JDBC的事务管理器为DataSourceTransactionManager

 

 <!-- Sharding start -->
	<bean id="shardingTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="shardingDataSource" />
	</bean>
 首先,我们先看Spring是如何兼容JDBC驱动的事务的

 

DataSourceTransactionManager和JDBC事务的具体封装在spring-jdbc-xxx.jar中,DataSourceTransactionManager的父类AbstractPlatformTransactionManager在spring-tx-xxx.jar中,其中后者为spring对事务的抽象层,前者是JDBC事务的具体实现。代码中设计底层的交给DataSourceTransactionManager子类实现,AbstractPlatformTransactionManager封装上层接口,事务的调用都走上层接口。

接下来我们从上面的六步着手,逐层下探

1.  事务的创建,方法的调用流程如下

TransactionAspectSupport.createTransactionIfNecessary->AbstractPlatformTransactionManager.getTransaction->DataSourceTransactionManager.*

 

AbstractPlatformTransactionManager.getTransaction方法

 

public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {

//调用DataSourceTransactionManager获得transaction句柄对象
Object transaction = doGetTransaction();

//如果事务存在,根据事务的传播类型,进行对应的处理
if (isExistingTransaction(transaction)) {
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}

//以前不存在事务,doBegin启动事务
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
			definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			doBegin(transaction, definition);
 
具体分析 针对已经存在事务的情况,handleExistingTransaction是如何处理的

 

	private TransactionStatus handleExistingTransaction(
			TransactionDefinition definition, Object transaction, boolean debugEnabled)
			throws TransactionException {

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
//该方法绝对不能在事务范围内执行。如果在就抛例外。只有该方法没有关联到任何事务,才正常执行。
		}

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
//声明方法不需要事务。如果方法没有关联到一个事务,容器不会为他开启事务,如果方法在一个事务中被调用,该事务会被挂起,调用结束后,原先的事务会恢复执行。
suspend(transaction);
		}

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
//不管是否存在事务,该方法总汇为自己发起一个新的事务。如果方法已经运行在一个事务中,则原有事务挂起,新的事务被创建。
suspend(transaction);
}

if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
//如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。
}

   总结一下,AbstractPlatformTransactionManager.getTransaction共涉及DataSourceTransactionManager的四个方法,具体方法的分析移步到http://blue2048.iteye.com/admin/blogs/2176676

  1. doGetTransaction

  2. isExistingTransaction

  3. doBegin

  4. doSuspend

2.  事务的回滚,方法的调用流程如下

TransactionAspectSupport.completeTransactionAfterThrowing->AbstractPlatformTransactionManager.processRollback->DataSourceTransactionManager.doRollback

 

protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {
    if (txInfo.transactionAttribute.rollbackOn(ex)) {
        //如果对ex敏感,回滚事务
	txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
    }else {
        //不对ex敏感,提交事务
	txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
    }
}
 
2.  事务的提交,方法的调用流程如下

 

TransactionAspectSupport.commitTransactionAfterReturning->AbstractPlatformTransactionManager.processCommit->DataSourceTransactionManager.*

 
//事务如果是最外层事务,则进行真是提交,否则执行resume
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
    if (status.isNewTransaction()) {
        doCommit(status);
    }
    cleanupAfterCompletion(status);
}

private void cleanupAfterCompletion(DefaultTransactionStatus status) {
    doCleanupAfterCompletion(status.getTransaction());
    resume(status.getTransaction(), (SuspendedResourcesHolder) status.getSuspendedResources());
}

protected final void resume(Object transaction, SuspendedResourcesHolder resourcesHolder)
			throws TransactionException {
    doResume(transaction, suspendedResources);
}

 总结一下,AbstractPlatformTransactionManager.processCommit共涉及DataSourceTransactionManager的四个方法,具体方法的分析移步到http://blue2048.iteye.com/admin/blogs/2176676

  1. doCommit

  2. doCleanupAfterCompletion

  3. doResume

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值