第19章 Spring事务王国的架构(四)

第19章 Spring事务王国的架构

19.2 和平年代

19.2.2 TransactionStatus

2. 窥一斑而知全豹

PlatformTransactionManager的各个子类在实现时,基本上遵循统一的结构和理念。所以,我们不妨选择以DataSourceTransactionManager这一实现类作为切入点,以管中窥豹之势,一探Spring的抽象事务框架中各个PlatformTransactionManager实现类的奥秘所在。

不过,在开始之前,我们有必要先了解如下几个概念。

  • transaction object。**transaction object承载了当前事务的必要信息,**PlatformTransactionManager实现类可以根据transaction object所提供的信息来决定如何处理当前事务。transaction object的概念类似于JTA规范中的javax.transaction.Transaction定义。
  • TransactionSynchronization。TransactionSynchronization是可以注册到事务处理过程中的回调接口。它就像是事务处理的事件监听器,当事务处理的某些规定时点发生时,会调用TransactionSynchronization上的一些方法来执行相应的回调逻辑,如在事务完成后清理相应的系统资源等操作。Spring事务抽象框架所定义的TransactionSynchronization类似于JTA规范的javax.transaction.Synchronization,但比JTA的Synchronization提供了更多的回调方法,允许我们对事务的处理添加更多的回调逻辑。
  • TransactionSynchronizationManager。类似于JTA规范中的javax.transaction.TransactionSynchronizationRegistry,**我们通过TransactionSynchronizationManager来管理TransactionSynchronization、当前事务状态以及具体的事务资源。**在介绍Spring事务框架实现原理的原型中,我们提到会将具体的事务资源,比如java.sql.Connection或者HibernateSession绑定到线程,TransactionSynchronizationManager就是这些资源绑定的目的地。当然,从该类的名字也可以看出,它更多关注与事务相关的Synchronization的管理。

将它们与JTA规范中定义的接口相提并论,是因为这些概念只限于局部场景中对应的PlatformTransactionManager实现类使用,而JtaTransactionManager直接就使用对应的JTA产品提供的对应设施了,JtaTransactionManager的最终工作都是委派给具体的JTA实现产品,记得吗?

好的,有了这些铺垫,我们开始进入正题…

Spring的事务抽象框架以PlatformTransactionManager作为项层抽象接口,具体的实现交给不同的实现类,使用对象可以根据当前场景,选择使用或者替换哪一个具体的实现类。从这个层次看(见图19-10),整个框架的设计是以Strategy模式为基础的。不过,从各个实现类的继承层次上来看,Spring事务框架的实现则更多地依赖于模板方法模式。

image-20220610175723129

org.springframework.transaction.support.AbstractPlatformTransactionManager作为DataSourceTransactionManager的父类,以模板方法的形式封装了固定的事务处理逻辑,而只将与事务资源相关的操作以protected或者abstract方法的形式留给DataSourceTransactionManager来实现。作为模板方法父类,AbstractPlatformTransactionManager替各子类实现了以下固定的事务内部处理逻辑:

  • 判定是否存在当前事务,然后根据判断结果执行不同的处理逻辑;
  • 结合是否存在当前事务的情况,根据TransactionDefinition中指定的传播行为的不同语义执行后继逻辑;
  • 根据情况挂起或者恢复事务;
  • 提交事务之前检查readOnly字段是否被设置,如果是的话,以事务的回滚代替事务的提交;
  • 在事务回滚的情况下,清理并恢复事务状态;
  • 如果事务的Synchonization处于active状态,在事务处理的规定时点触发注册的Synchonization回调接口。

这些固定的事务内部处理逻辑大都体现在以下几个主要的模板方法中:

image-20220610175929896

我们可不打算把这几个模板方法都讲一遍。毕竟,只要了解了前面两三个模板方法的流程,整个事务处理的图景基本上就可以展现在我们眼前了。

我们先从第一个模板方法getTransaction(TransactionDefinition)开始。getTransaction(TransactionDefinition)的主要目的是开启一个事务,但需要在此之前判断一下之前是否存在一个事务。如果存在,则根据TransactionDefinition中的传播行为决定是挂起当前事务还是抛出异常。同样的,不存在事务的情况下,也需要根据传播行为的具体语义来决定如何处理。

getTransaction(TransactionDefinition)方法的处理逻辑,基本上按照下面的流程执行。

(1)获取transactionobject,以判断是否存在当前事务。

扫描二维码关注公众号,回复: 14294352 查看本文章
Object transaction = doGetTransaction();

以上这行代码有如下两点需要申明。

获取的transactionobject类型会因具体实现类的不同而各异,DataSourceTransactionManager会返回DataSourceTransactionManager.DataSourceTransactionObject类型实例,HibernateTransactionManager会返回HibernateTransactionManager.HibernateTransactionObject类型的实例,等等。AbstractPlatformTransactionManager不需要知道具体实现类返回的transactionobject具体类型是什么,因为最终对transaction object的依赖都将通过方法参数进行传递,只要具体的实现类在取得transaction object参数后知道如何转型就行,所以,这一步返回的transaction为Object类型。

doGetTransaction()getTransaction(TransactionDefinition)模板方法公开给子类来实现的abstract类型方法。DataSourceTransactionManager在实现doGetTransaction()方法逻辑的时候,会从TransactionSynchronizationManager获取绑定的资源,然后添加到DataSourceTransactionObject之后返回。以此类推,其他AbstractPlatformTransactionManager子类都采用类似的逻辑实现了doGetTransaction()方法。

(2)获取Log类的debug信息,避免之后的代码重复。如以下代码所示:

boolean debugEnabled = logger.isDebugEnabled();
if(debugEnabled) {
    
    
	logger.debug("Using transaction object [" + transaction +"]");
}

debugEnabled将以方法参数的形式在各方法调用间传递,以避免每次都调用logger.isDebugEnabled()获取debug日志状态。这一步与具体的事务处理流程关系不大。

(3)检查TransactionDefinition参数合法性。如以下代码所示:

if (definition == null){
    
    
  // Use defaults if not transaction definition given.
  definition = new DefaultTransactionDefinition();
}

如果definition参数为空,则创建一个DefaultTransactionDefinition实例以提供默认的事务定义数据。

(4)根据先前获得的transaction object判断是否存在当前事务,根据判定结果采取不同的处理方式。如以下代码所示:

if(isExistingTransaction(transaction)) {
    
    
	// Existing transaction found -> check propagation behavior to find out how to behave.
	return handleExistingTransaction(definition, transaction, debugEnabled);
}

默认情况下,isExistingTransaction(transaction)返回false,该方法需要具体子类根据情况进行覆写。对于DataSourceTransactionManager来说,它会根据传入的transaction所记载的信息进行判断,如下所示:

DataSourceTransactionObject txObject = (DataSourceTransactionObject)transaction;
return(txObject.getConnectionHolder() != null && txObject.getConnectionHolder().isTransactionActive());

对于HibernateTransactionManager来说,则会将transaction强制转型为HibernateTransactionObject,然后根据HibernateTransactionObject所记载的信息来判断之前是否存在一个事务。其他具体实现类对isExistingTransaction(transaction)的处理亦是如此。

不管isExistingTransaction(transaction)返回结果如何,下面的处理主体上都是以TransactionDefinition中的传播行为为中心进行的。比如同样是PROPAGATION_REQUIRED,在存在当前事务与不存在当前事务两种情况下的处理是不同的,前者会使用之前的事务,后者则会创建新的事务,其他的传播行为的处理也是按照不同的场景分别处理。

(a)如果isExistingTransaction(transaction)方法返回true,即存在当前事务的情况下,由handleExistingTransaction()方法统一处理存在当前事务,应该如何创建事务对应的TransactionStatus实例并返回。如果definition定义的传播行为是PROPAGATION_NEVER,抛出异常并退出。如下:

if(definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
    
    
	throw new IllegalTransactionStateException("Existing transaction found for transaction marked with propagation 'never'");
}

这是由TransactionDefinition.PROPAGATION_NEVER的语义决定的。

如果definition定义的传播行为是PROPAGATION_NOT_SUPPORTED,则挂起当前事务,然后返回。如下:

if(definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_
SUPPORTED) {
    
    
	if(debugEnabled) {
    
    
		logger.debug("Suspendingcurrenttransaction");
  }
	Object suspendedResources = suspend(transaction);
	boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
	return new TransactionStatus(definition, null, false, newSynchronization, debugEnabled,suspendedResources);
}

newTransactionStatus()方法返回一个DefaultTransactionstatus实例,因为我们挂起了当前事务。而PROPAGATION_NOT_SUPPORTED不需要事务,所以,返回的DefaultTransactionStatus不包含transaction object的信息(构造方法第二个参数)。

如果definition定义的传播行为是PROPAGATION_REQUIRES_NEW,则同样挂起当前事务,并开始一个新的事务并返回。如下:

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 {
    
    
		doBegin(transaction, definition);
  }
	catch(TransactionException beginEx) {
    
    
		try {
    
    
			resume(transaction, suspendedResources);
    }
		catch(TransactionException resumeEx) {
    
    
			logger.error("Inner transaction begin exception overridden by outer transaction resume exception", beginEx);
			throw resuneEx;
    }
		throw beginEx;
  }
	boolean newSynchronization = (getTransactionSynchronization()!=SYNCHRONIZATION_NEVER);
	return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
}

AbstractPlatformTransactionManager首先将当前事务挂起,然后调用doBegin()方法开始新的事务。如果开始事务过程中出现异常,那么恢复之前挂起的事务。doBegin(transaction, definition)方法为abstract方法,需要具体子类来实现。

在DataSourceTransactionManager中,doBegin()方法会首先检查传入的transaction,以提取必要信息判断之前是否存在绑定的connection信息。如果没有,则从DataSource中获取新的connection,然后将其AutoCommit状态改为false,并绑定到TransactionSynchronizationManager。

猜你喜欢

转载自blog.csdn.net/qq_34626094/article/details/125358294