理解 Transactional 的工作原理


本文由 簡悅 SimpRead 轉碼, 原文地址 www.kailing.pub 引言

寫這篇博文有個來由,是為了解決博主遇到的多數據源的事務問題(用不了 JTA),所以深入到 spring-tx 的源碼去學習了一番,非常有收獲,最后博主的分布式事務問題也迎刃而解了,這個文章算個開篇,關於如何處理多數據源事務,待下文分解。本文涉及到的技術包含 spring aop 的使用、spring bean 生命周期等,如果能夠真正理解 Transactional 的工作原理,對排查事務相關的問題有非常大的幫助。

spring-tx 版本:5.0.2

工作機制簡述

先來看一張官方的事務簡圖:

spring 定義了 @Transactional 注解,基於 AbstractBeanFactoryPointcutAdvisor、StaticMethodMatcherPointcut、MethodInterceptor 的 aop 編程模式,增強了添加 @Transactional 注解的方法。同時抽象了事務行為為 PlatformTransactionManager(事務管理器)、TransactionStatus(事務狀態)、TransactionDefinition(事務定義) 等形態。最終將事務的開啟、提交、回滾等邏輯嵌入到被增強的方法的前后,完成統一的事務模型管理。

事務 aop 核心類釋義

@Transactional

事務注解,用於定位 aop 的切入點,事務注解里包含了完整事務的所有基本屬性,常見的屬性如:

  • transactionManager:事務管理器
  • propagation:傳播行為定義,枚舉類型,是 spring 獨有的事務行為設計,默認為 PROPAGATION_REQUIRED(支持當前事務,不存在則新建)
  • isolation:隔離級別,對應數據庫的隔離級別實現,mysql 默認的隔離級別是 read-committed
  • timeout:超時時間,默認使用數據庫的超時,mysql 默認的事務等待超時為 5 分鍾
  • readOnly:是否只讀,默認是 false
  • rollbackFor:異常回滾列表,默認的是 RuntimeException 異常回滾

TransactionAttribute

事務屬性抽象接口類,承載了 @Transactional 注解里的所有屬性,實現類的繼承關系如下類結構圖,這個實例在被注解解析器創建好后,會在事務上下文中傳遞

SpringTransactionAnnotationParser

見名知意,這個類是 spring 的事務注解解析器,實現自 TransactionAnnotationParser 接口,是 spring 管理的事務解析器,用於解析 @Transactional 注解,將注解里的屬性設置到 TransactionAttribute 的實現類屬性里。除了這個,另還有兩個實現,分別是 JTA 事務注解解析器,和 EJB 事務注解管理解析器,區別是解析的注解不同,spring 是 @Transactional,jta 是 javax.transaction.Transactional,EJB 是 javax.ejb.TransactionAttribute。這個地方應用和 apache dubbo2.7.x 版本解析 dubbo 的 @service 注解是一樣一樣的。關鍵代碼如下,通過 AnnotatedElementUtils 類,這個類在 spring-core 包下,找到注解屬性集 AnnotationAttributes,如果不為空,則包裝成事務屬性集返回

	@Override
	@Nullable
	public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
		AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
				element, Transactional.class, false, false);
		if (attributes != null) {
			return parseTransactionAnnotation(attributes);
		}
		else {
			return null;
		}
	}

AnnotationTransactionAttributeSource

見名知意,這個類是注解事務屬性集的源,怎么理解呢?spring 抽象了獲取事務屬性集的行為,而 AnnotationTransactionAttributeSource 正是 @Transactional 注解方式的事務屬性集收集實現。SpringTransactionAnnotationParser 就是作用於這個里面,用於發現 @Transactiona 注解的方法

TransactionAttributeSourcePointcut

也是見名知意,Pointcut 屬於 aop 的概念范疇,需要了解 spring aop 的知識才能看明白,這個就是 @Transactional 注解的切點,AnnotationTransactionAttributeSource 作用於此,用於尋找 @Transactiona 注解的方法,關鍵代碼如下:

	public boolean matches(Method method, Class targetClass) {
		TransactionAttributeSource tas = getTransactionAttributeSource();
		return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
	}

TransactionInterceptor

事務的攔截器。aop 編程里,有了切入點 Pointcut,就要有通知 advice,我們熟悉的 spring aop 里有前置、后置、環繞、異常等通知類型,TransactionInterceptor 屬於自定義通知模型實現,實現自 Advice 接口,類似於環繞通知,具體見類結構圖,如下:

核心方法如下:

	public Object invoke(MethodInvocation invocation) throws Throwable {
		// Work out the target class: may be {@code null}.
		// The TransactionAttributeSource should be passed the target class
		// as well as the method, which may be from an interface.
		Class targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		// Adapt to TransactionAspectSupport's invokeWithinTransaction...
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}

被 @Transactional 注解的方法,如果被 aop 正確的增強了,運行的時候都會進入到這個方法里面,如果你發現事務不生效啊等等問題,可以從這里開始定位真實原因

BeanFactoryTransactionAttributeSourceAdvisor

事務增強器,用於增強添加了 @Transactional 注解的方法,上面提到的這些核心類,最終都作用於這里,用於尋找 @Transactional 注解的方法和織入事務處理邏輯

ProxyTransactionManagementConfiguration

代理事務管理的配置類,上面介紹的這些事務 aop 編程相關的在這個里面組合配置生效的,同時,如果你有特殊的個性化的需求,也可以自定義注冊這個里面的實例。比如我嫌棄 @Transactional 注解太長了,想用 @Tx 注解。沒關系,直接定義個 TransactionAttributeSource 實現,解析 @Tx 的方法,然后注冊到 spring 的上線文中即可。代碼如:

@Configuration(proxyBeanMethods = false)
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
			TransactionAttributeSource transactionAttributeSource,
			TransactionInterceptor transactionInterceptor) {
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource);
		advisor.setAdvice(transactionInterceptor);
		if (this.enableTx != null) {
			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(
			TransactionAttributeSource transactionAttributeSource) {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource);
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}

事務抽象核心類釋義

PlatformTransactionManager

平台事務管理器,這是 Spring 事務基礎設施中的中心接口。它定義了三個最最基本的事務方法,getTransaction 獲取事務,包含了事務開啟的行為,commit 提交事務,rollback 回滾事務。代碼如下:

public interface PlatformTransactionManager extends TransactionManager {
	TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException;
	void commit(TransactionStatus status) throws TransactionException;
	void rollback(TransactionStatus status) throws TransactionException;
}

在 spring-tx 中並沒有提供真正的實現類,只提供了一個抽象派生類 AbstractPlatformTransactionManager,並建議其他實現基於這個派生類,因為它預先實現了定義的傳播行為並處理事務同步處理。子類必須為底層事務的特定狀態實現模板方法,例如: begin、suspend、resume、commit 等。我們平時常見的實現有:JpaTransactionManager、JtaTransactionManager、DataSourceTransactionManager 等。事務管理器和事務 aop 處理的邏輯本身沒有任何耦合,只需將 PlatformTransactionManager 實例注冊到 spring 上下文中即可,事務攔截器會通過獲取到 @Transactional 里的 transactionManager 屬性去上下文中尋找事務管理器,並將其緩存起來,見 TransactionAspectSupport.java 里的 determineTransactionManager 方法

	protected PlatformTransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
		// Do not attempt to lookup tx manager if no tx attributes are set
		if (txAttr == null || this.beanFactory == null) {
			return asPlatformTransactionManager(getTransactionManager());
		}

		String qualifier = txAttr.getQualifier();
		if (StringUtils.hasText(qualifier)) {
			return determineQualifiedTransactionManager(this.beanFactory, qualifier);
		}
		else if (StringUtils.hasText(this.transactionManagerBeanName)) {
			return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
		}
		else {
			PlatformTransactionManager defaultTransactionManager = asPlatformTransactionManager(getTransactionManager());
			if (defaultTransactionManager == null) {
				defaultTransactionManager = asPlatformTransactionManager(
						this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY));
				if (defaultTransactionManager == null) {
					defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
					this.transactionManagerCache.putIfAbsent(
							DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
				}
			}
			return defaultTransactionManager;
		}
	}

TransactionStatus

事務狀態抽象,用這個類的實現來維護當前的事務狀態,spring-tx 里提供了默認的實現 DefaultTransactionStatus。一般情況下這個不需要我們關心,它和 PlatformTransactionManager 是成對存在的,心細的你可能已經發現了,PlatformTransactionManager 里的三個事務行為傳遞的就是 TransactionStatus。我們知道事務 aop 增強了添加 @Transactional 的方法,在執行方法前調用 PlatformTransactionManager.getTransaction 開啟事務, 之后調用 commit 方法提交事務,提交事務的入參 TransactionStatus 就是開啟事務獲得的。參見 TransactionAspectSupport.java 里的 createTransactionIfNecessary 方法

TransactionDefinition

事務定義,對應了 TransactionAttribute,最終通過 aop 得到的 TransactionAttribute 里的屬性會被傳遞到 TransactionDefinition 里,所以 TransactionDefinition 里也包含了所有事務相關的屬性,PlatformTransactionManager.getTransaction 正是通過這個里面的屬性去獲取的事務。AbstractPlatformTransactionManager 派生類里也是通過這個里面的屬性去判斷協調 spring 的事務傳播行為的

結語

當梳理完 spring-tx 模塊的整個結構和工作方式后,仿佛拉開了 spring 事務管理的面紗,很多事務的執行細節一覽無余。很多事務相關的問題也就很容易解釋了。比如常見的類中的方法直接調用方法事務不生效等問題,以及可以非常清晰的理解 spring 的傳播行為的真正含義等。最后預告下,spring 對於多數據源的事務處理解決方案 ChainedTransactionManager


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM