日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

Spring TX源码分析

發(fā)布時(shí)間:2025/3/15 javascript 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring TX源码分析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、先思考一下

  • 什么是事務(wù)?
    事務(wù)是一系列數(shù)據(jù)庫(kù)操作的集合,在一個(gè)事務(wù)里,所有有關(guān)的數(shù)據(jù)庫(kù)操作一起提交或一起回滾
  • 事務(wù)用在什么地方?
    如果多個(gè)數(shù)據(jù)庫(kù)操作需要一起生效或一起失效,那么這些操作需要放在一個(gè)事務(wù)里面
  • 事務(wù)如何創(chuàng)建?
    用戶創(chuàng)建了針對(duì)數(shù)據(jù)庫(kù)操作的連接(java.sql.Connection)之后,就可以針對(duì)Connection進(jìn)行事務(wù)的操作,事務(wù)依賴于連接
  • 事務(wù)的基本操作?
    1. 開(kāi)啟事務(wù):Connection.setAutoCommit(false);關(guān)閉自動(dòng)提交則就開(kāi)啟了事務(wù)
    2. 提交事務(wù):Connection.commit();
    3. 回滾事務(wù):Connection.rollback();

關(guān)于事務(wù)的各種概念:


更詳細(xì)的參考

看源碼之前,如果有看AOP源碼的經(jīng)歷,會(huì)很有幫助,因?yàn)閟pring的事務(wù)就是基于AOP的

二、開(kāi)啟事務(wù)

  • 基于XML
  • 我們?cè)赽eans.xml中開(kāi)啟事務(wù)的應(yīng)用,需要添加

    <tx:annotation-driven transaction-manager="transactionManager"/>
    • tx:annotation-driven/注解的分析

    但凡這種注解,都有對(duì)應(yīng)的解析器,跟AOP功能的源碼一樣,解析器都實(shí)現(xiàn)了NamespaceHandlerSupport類,我們來(lái)獲取下NamespaceHandlerSupport的實(shí)現(xiàn)類都有哪些


    看名字就是TxNamespaceHandler類,我們來(lái)看下這個(gè)類有哪些內(nèi)容

    • TxNamespaceHandler
    public class TxNamespaceHandler extends NamespaceHandlerSupport {...@Overridepublic void init() {registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());// 這句代碼負(fù)責(zé)解析annotation-drivenregisterBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());} }

    Spring會(huì)默認(rèn)調(diào)用其init()方法,annotation-driven對(duì)應(yīng)的是AnnotationDrivenBeanDefinitionParser解析器,我們來(lái)看下這個(gè)解析器的作用

    • AnnotationDrivenBeanDefinitionParser的作用分析
    public BeanDefinition parse(Element element, ParserContext parserContext) {registerTransactionalEventListenerFactory(parserContext);String mode = element.getAttribute("mode");if ("aspectj".equals(mode)) {// mode="aspectj"registerTransactionAspect(element, parserContext);}else {// 默認(rèn)為proxy模式// 所以要執(zhí)行該句AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);}return null; }
    • AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
    public static void configureAutoProxyCreator(Element element, ParserContext parserContext) { AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);// txAdvisorBeanName值為 org.springframework.transaction.config.internalTransactionAdvisorString txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {Object eleSource = parserContext.extractSource(element);// 1.注冊(cè)類AnnotationTransactionAttributeSource到Spring中RootBeanDefinition sourceDef = new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");sourceDef.setSource(eleSource);sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);// 2.注冊(cè)類TransactionInterceptor到Spring中RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);interceptorDef.setSource(eleSource);interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);registerTransactionManager(element, interceptorDef);interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);// 3.注冊(cè)類BeanFactoryTransactionAttributeSourceAdvisor到Spring中RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);advisorDef.setSource(eleSource);advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);if (element.hasAttribute("order")) {advisorDef.getPropertyValues().add("order", element.getAttribute("order"));}parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));parserContext.registerComponent(compositeDef);} }

    總結(jié):通過(guò)以上的分析可知,tx:annotation-driven/的主要功能就是將以下四個(gè)類注冊(cè)到Spring容器中

    • AnnotationTransactionAttributeSource
    • TransactionInterceptor(主要的攔截功能都在這里實(shí)現(xiàn))
    • BeanFactoryTransactionAttributeSourceAdvisor(創(chuàng)建bean的代理類的時(shí)候該Advisor會(huì)被用上)
    • InfrastructureAdvisorAutoProxyCreator:用于創(chuàng)建事務(wù)代理
    • InfrastructureAdvisorAutoProxyCreator功能分析

    其實(shí)現(xiàn)了BeanPostProcessor接口,則Spring在創(chuàng)建bean的時(shí)候,會(huì)默認(rèn)調(diào)用InfrastructureAdvisorAutoProxyCreator的postProcessAfterInitialization()方法,然后就是wrapIfNecessary,跟AOP的流程完全一致

  • 基于注解的@EnableTransactionManagement

  • 可以看到,注冊(cè)了AutoProxyRegistrar(是一個(gè)BeanPostProcessor)和ProxyTransactionManagementConfiguration(用于解析事務(wù)屬性)

    • ProxyTransactionManagementConfiguration
    • 該類是一個(gè)配置Bean
    • 目的:創(chuàng)建事務(wù)的切面,跟AOP的區(qū)別就在這里,AOP的切面是我們自己定義的,而事務(wù)的切面是Spring給我們生成的
    @Configuration @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {//想IOC容器中導(dǎo)入事務(wù)增強(qiáng)器(BeanFactoryTransactionAttributeSourceAdvisor),// 事務(wù)注解@Transactional的解析器(AnnotationTransactionAttributeSource)// 和事務(wù)方法攔截器(TransactionInterceptor);/**事務(wù)增強(qiáng)器(Advisor),在事務(wù)類創(chuàng)建的時(shí)候,被AutoProxyRegistrar導(dǎo)入的組件InfrastructureAdvisorAutoProxyCreator攔截,InfrastructureAdvisorAutoProxyCreator攔截的邏輯就是增強(qiáng)事務(wù)類的事務(wù)方法, 而BeanFactoryTransactionAttributeSourceAdvisor作為增強(qiáng)器,與需要增強(qiáng)的方法(這里是指被@Transactional標(biāo)記的方法)進(jìn)行匹配,匹配成功的增強(qiáng)器,最后轉(zhuǎn)成攔截器(MethodInterceptor,就是下面的TransactionInterceptor),然后與目標(biāo)方法一起在攔截器鏈中被執(zhí)行,達(dá)到方法增強(qiáng)的效果;BeanFactoryTransactionAttributeSourceAdvisor的繼承關(guān)系如下:BeanFactoryTransactionAttributeSourceAdvisor--AbstractBeanFactoryPointcutAdvisor--AbstractPointcutAdvisor--PointcutAdvisor--AdvisorAOP中AspectJPointcutAdvisor的繼承關(guān)系如下,與AbstractPointcutAdvisor一樣,都實(shí)現(xiàn)PointcutAdvisor--AspectJPointcutAdvisor--PointcutAdvisor--Advisor*/@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();advisor.setTransactionAttributeSource(transactionAttributeSource());advisor.setAdvice(transactionInterceptor());advisor.setOrder(this.enableTx.<Integer>getNumber("order"));return advisor;}/**@ Transactional注解的解析類;負(fù)責(zé)解析事務(wù)方法上@Transactional中的各個(gè)參數(shù)配置,解析的時(shí)機(jī)是在創(chuàng)建事務(wù)類之后被增強(qiáng)的時(shí)候,匹配事務(wù)方法的時(shí)候一起被解析了AnnotationTransactionAttributeSource的繼承關(guān)系如下:AnnotationTransactionAttributeSource--AbstractFallbackTransactionAttributeSource--TransactionAttributeSource通過(guò)方法org.springframework.transaction.interceptor.AbstractFallbackTransactionAttributeSource.getTransactionAttribute(Method, Class<?>)解析出事務(wù)信息TransactionAttribute;AnnotationTransactionAttributeSource在方法findTransactionAttribute(Class<?>)中依賴于SpringTransactionAnnotationParser在解析事務(wù)類時(shí),綁定事務(wù)方法與增強(qiáng)器的時(shí)候進(jìn)行@Transactional注解解析;*/@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public TransactionAttributeSource transactionAttributeSource() {return new AnnotationTransactionAttributeSource();}/**被@Transactional標(biāo)記的事務(wù)方法的攔截器,實(shí)際是一個(gè)MethodInterceptor保存了事務(wù)屬性信息,事務(wù)管理器;在目標(biāo)方法執(zhí)行的時(shí)候;執(zhí)行攔截器鏈;*/@Bean@Role(BeanDefinition.ROLE_INFRASTRUCTURE)public TransactionInterceptor transactionInterceptor() {TransactionInterceptor interceptor = new TransactionInterceptor();interceptor.setTransactionAttributeSource(transactionAttributeSource());if (this.txManager != null) {interceptor.setTransactionManager(this.txManager);}return interceptor;} }
    • AutoProxyRegistrar


    可以看到也注冊(cè)了一個(gè)InfrastructureAdvisorAutoProxyCreator


    跟xml的方式殊途同歸:也實(shí)現(xiàn)了BeanPostProcessor接口,則Spring在創(chuàng)建bean的時(shí)候,會(huì)默認(rèn)調(diào)用InfrastructureAdvisorAutoProxyCreator的postProcessAfterInitialization()方法,然后就是wrapIfNecessary,跟AOP的流程完全一致

    那么后置處理bean有了,切面也有了,就可以創(chuàng)建事務(wù)代理了

    三、執(zhí)行事務(wù)

    跟AOP一樣,以JdkDynamicProxy一樣,調(diào)用代理,觸發(fā)ReflectiveMethodInvocation的執(zhí)行方法

    retVal = invocation.proceed();

    進(jìn)而執(zhí)行到

    代碼跟到這里,跟AOP又有一個(gè)不同的點(diǎn),就是這個(gè)invoke的實(shí)現(xiàn)是TransactionInterceptor類,該類專門處理事務(wù)切面的執(zhí)行

    //TransactionInterceptorpublic Object invoke(MethodInvocation invocation) throws Throwable {//計(jì)算出目標(biāo)類:可能是 {@code null}。 TransactionAttributeSource 應(yīng)該傳遞目標(biāo)類以及方法,該方法可能來(lái)自接口。Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);//適配TransactionAspectSupport的invokeWithinTransaction...return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);}

    進(jìn)而進(jìn)入invokeWithinTransaction

    @Nullable//TransactionAspectSupportprotected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation) throws Throwable {// If the transaction attribute is null, the method is non-transactional.// 如果事務(wù)屬性為空,則該方法是非事務(wù)性的。TransactionAttributeSource tas = getTransactionAttributeSource();//拿到事務(wù)5個(gè)屬性的值,@Transactional(propagation = Propagation.REQUIRED,isolation = Isolation.DEFAULT )final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);//獲取事務(wù)管理器,由我們通過(guò)配置指定。事務(wù)管理的底層一定會(huì)與數(shù)據(jù)庫(kù)有關(guān),所以會(huì)注入數(shù)據(jù)源等屬性final PlatformTransactionManager tm = determineTransactionManager(txAttr);//切入點(diǎn),也就是需要控制事務(wù)的目的方法(update...)final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {// Standard transaction demarcation with getTransaction and commit/rollback calls.//使用 getTransaction 和 commitRollback 調(diào)用進(jìn)行標(biāo)準(zhǔn)事務(wù)劃分,這一句是最難理解的//ifNecessary?其實(shí)就是根據(jù)事務(wù)屬性決定是否開(kāi)啟事務(wù)TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);Object retVal;try {// This is an around advice: Invoke the next interceptor in the chain.// This will normally result in a target object being invoked.// 源方法運(yùn)行retVal = invocation.proceedWithInvocation();}catch (Throwable ex) {// target invocation exception//出現(xiàn)異常時(shí)則回滾事務(wù),注意:如果是Exception不會(huì)回滾,只有RunTimeException或者Error來(lái)及其子類才會(huì)回滾completeTransactionAfterThrowing(txInfo, ex);throw ex;}finally {//重置 TransactionInfo ThreadLocal。 在所有情況下都調(diào)用它:異常或正常返回cleanupTransactionInfo(txInfo);}//提交事務(wù)//TransactionManager調(diào)用Connection.commit()commitTransactionAfterReturning(txInfo);return retVal;}

    進(jìn)入createTransactionIfNecessary

    protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {// If no name specified, apply method identification as transaction name.// 如果未指定名稱,則應(yīng)用方法標(biāo)識(shí)作為事務(wù)名稱if (txAttr != null && txAttr.getName() == null) {txAttr = new DelegatingTransactionAttribute(txAttr) {@Overridepublic String getName() {return joinpointIdentification;}};}//記錄當(dāng)前事務(wù)的狀態(tài),是否新事務(wù),是否只讀事務(wù),是否開(kāi)啟同步?TransactionStatus status = null;if (txAttr != null) {if (tm != null) {//獲取事務(wù)的狀態(tài)status = tm.getTransaction(txAttr);}else {if (logger.isDebugEnabled()) {logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +"] because no transaction manager has been configured");}}}return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);}

    當(dāng)TransactionAttribute為null,則創(chuàng)建一個(gè)TransactionInfo

    protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,@Nullable TransactionAttribute txAttr, String joinpointIdentification,@Nullable TransactionStatus status) {/** 根據(jù)給定的事務(wù)屬性、事務(wù)管理器、方法連接點(diǎn)描述字符串(全限定方法名)信息創(chuàng)建一個(gè)事務(wù)信息對(duì)象TransactionInfo*/TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);// 如果事務(wù)屬性不為nullif (txAttr != null) {// We need a transaction for this method...if (logger.isTraceEnabled()) {logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");}//那么設(shè)置事務(wù)狀態(tài),這里就表示為當(dāng)前方法創(chuàng)建了一個(gè)事務(wù)txInfo.newTransactionStatus(status);}// 如果事務(wù)屬性為null,那么表示當(dāng)前方法必須要?jiǎng)?chuàng)建事務(wù)else {if (logger.isTraceEnabled()) {logger.trace("No need to create transaction for [" + joinpointIdentification +"]: This method is not transactional.");}}//始終將最新的TransactionInfo綁定到當(dāng)前線程,即使我們沒(méi)有在此處創(chuàng)建新的事務(wù)也是如此。//也就是將當(dāng)前線程的最新事務(wù)棧設(shè)置為當(dāng)前對(duì)象存入transactionInfoHolder中//這保證即使此方面未創(chuàng)建任何事務(wù),也將正確管理TransactionInfo堆棧。txInfo.bindToThread();return txInfo; }
    • 這里要先介紹一下TransactionInfo,這是SpringTX的核心,TransactionInfo是TransactionAspectSupport的內(nèi)部類,用來(lái)保存線程的執(zhí)行方法時(shí)的事務(wù)信息。內(nèi)部保存了事務(wù)管理器transactionManager、事務(wù)屬性transactionAttribute、全路徑方法名joinpointIdentification。還保存了當(dāng)前方法的事務(wù)transactionStatus,以及前一個(gè)方法的事務(wù)信息對(duì)象oldTransactionInfo。
    protected final class TransactionInfo {@Nullable//事務(wù)管理器private final PlatformTransactionManager transactionManager;@Nullable//事務(wù)屬性private final TransactionAttribute transactionAttribute;//連接點(diǎn)描述字符串(方法的全限定名),主要用于記錄日志private final String joinpointIdentification;@Nullable//事務(wù)狀態(tài)private TransactionStatus transactionStatus;@Nullable//老的事務(wù)信息對(duì)象private TransactionInfo oldTransactionInfo;public TransactionInfo(@Nullable PlatformTransactionManager transactionManager,@Nullable TransactionAttribute transactionAttribute, String joinpointIdentification) {this.transactionManager = transactionManager;this.transactionAttribute = transactionAttribute;this.joinpointIdentification = joinpointIdentification;}public PlatformTransactionManager getTransactionManager() {Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");return this.transactionManager;}@Nullablepublic TransactionAttribute getTransactionAttribute() {return this.transactionAttribute;}/*** Return a String representation of this joinpoint (usually a Method call)* for use in logging.*///返回此連接點(diǎn)的String表示形式(通常是方法調(diào)用),以用于日志記錄。public String getJoinpointIdentification() {return this.joinpointIdentification;}public void newTransactionStatus(@Nullable TransactionStatus status) {this.transactionStatus = status;}@Nullablepublic TransactionStatus getTransactionStatus() {return this.transactionStatus;}/*** Return whether a transaction was created by this aspect,* or whether we just have a placeholder to keep ThreadLocal stack integrity.*///返回是否是通過(guò)此切面創(chuàng)建的事務(wù),或者是否只是一個(gè)占位符以保持ThreadLocal堆棧完整性。即當(dāng)前方法是否新建了事務(wù)。public boolean hasTransaction() {return (this.transactionStatus != null);}private void bindToThread() {向線程公開(kāi)當(dāng)前的TransactionStatus,并保留所有現(xiàn)有的老的TransactionStatus,以在此事務(wù)完成后恢復(fù)。// Expose current TransactionStatus, preserving any existing TransactionStatus// for restoration after this transaction is complete.this.oldTransactionInfo = transactionInfoHolder.get();transactionInfoHolder.set(this);}private void restoreThreadLocalStatus() {// Use stack to restore old transaction TransactionInfo.// Will be null if none was set.// 使用堆棧還原舊的事務(wù)TransactionInfo。如果未設(shè)置,則為null。transactionInfoHolder.set(this.oldTransactionInfo);}@Overridepublic String toString() {return (this.transactionAttribute != null ? this.transactionAttribute.toString() : "No transaction");}}

    如果事務(wù)屬性不為空,那么走getTransaction獲取/開(kāi)啟事務(wù)分支。在createTransactionIfNecessary方法中,如果存在事務(wù)屬性TransactionAttribute,并且存在事務(wù)管理器PlatformTransactionManager,那么將調(diào)用事務(wù)管理器的getTransaction方法根據(jù)為當(dāng)前方法配置的事務(wù)定義的屬性嘗試獲取事務(wù),將返回一個(gè)TransactionStatus對(duì)象。該方法是事務(wù)管理的核心方法,其骨干實(shí)現(xiàn)位于抽象實(shí)現(xiàn)類AbstractPlatformTransactionManager中,該方法根據(jù)配置的各種事務(wù)傳播行為做出不同的處理,方法執(zhí)行完畢將可能開(kāi)啟了新事物,也可能沒(méi)有開(kāi)啟,甚至拋出異常。AbstractPlatformTransactionManager的設(shè)計(jì)基于模版方法模式,他提供了處理流程,并且提供了一系列的do……模版方法供子類來(lái)實(shí)現(xiàn)自己的邏輯。

    getTransaction方法的大概邏輯為:

  • 首先通過(guò)doGetTransaction方法獲取一個(gè)內(nèi)部事務(wù)對(duì)象,該方法由具體的事務(wù)管理器子類自己實(shí)現(xiàn),返回的對(duì)象也是不一樣的,對(duì)于DataSourceTransactionManager這里獲取的實(shí)際上是一個(gè)DataSourceTransactionObject,其內(nèi)部可能會(huì)包含當(dāng)前數(shù)據(jù)的連接以及當(dāng)前的事務(wù)信息,也可能沒(méi)有(比如首次進(jìn)入事務(wù)方法)。
  • 通過(guò)isExistingTransaction方法判斷事物對(duì)象內(nèi)部的數(shù)據(jù)庫(kù)連接connectionHolder是否不為null并且是否已經(jīng)開(kāi)啟過(guò)了事務(wù)。
      • 如果條件都滿足,那么表示此前已經(jīng)開(kāi)啟過(guò)了事務(wù),即存在外層事務(wù),隨后調(diào)用handleExistingTransaction方法統(tǒng)一處理這種情況,比如加入當(dāng)前事務(wù)、新建事務(wù)、拋出異常等等邏輯。
  • 如果不都滿足,即不存在外層事務(wù),那么說(shuō)明當(dāng)前的事務(wù)方法就是最外層的事務(wù)方法,那么走下面的邏輯。
      • 校驗(yàn)為當(dāng)前事務(wù)方法設(shè)置的事務(wù)超時(shí)時(shí)間,如果小于默認(rèn)超時(shí)時(shí)間(-1),將會(huì)拋出異常。
      • 如果為當(dāng)前事務(wù)方法設(shè)置的傳播行為PROPAGATION_MANDATORY,該傳播行為的含義是:如果當(dāng)前存在事務(wù),則當(dāng)前方法加入到該事務(wù)中去,如果當(dāng)前不存在事務(wù),則當(dāng)前方法直接拋出異常。這里由于不存在外層事務(wù),那么這里就直接拋出異常:“No existing transaction found for transaction marked with propagation ‘mandatory’”。
      • 如果為當(dāng)前事務(wù)方法設(shè)置的傳播行為是PROPAGATION_REQUIRED或者PROPAGATION_REQUIRES_NEW或者PROPAGATION_NESTED,這些傳播行為的含義的共同點(diǎn)之一就是:如果當(dāng)前不存在事務(wù),就創(chuàng)建一個(gè)新事務(wù)運(yùn)行。這里由于不存在外層事務(wù),那么這里就直接創(chuàng)建一個(gè)新事物。
        • 首先調(diào)用suspend方法首先掛起事務(wù)同步,然后再委派給doSuspend模板方法掛起事務(wù),將返回被掛起的資源,用于后續(xù)恢復(fù),如果沒(méi)有事務(wù)同步也沒(méi)有事務(wù),那么將返回null。這里由于沒(méi)有已存在的事務(wù),那么參數(shù)傳遞null,一般也會(huì)將返回null。
        • 調(diào)用startTransaction方法,內(nèi)部依次調(diào)用newTransactionStatus方法創(chuàng)建TransactionStatus、doBegin方法真正的開(kāi)啟新的事務(wù)、prepareSynchronization方法準(zhǔn)備事務(wù)同步,最終返回TransactionStatus,該對(duì)象包含了創(chuàng)建的內(nèi)部事務(wù)對(duì)象,以及其他事務(wù)信息。
  • 否則,配置的事務(wù)的傳播行為就是剩下的三種:PROPAGATION_SUPPORTS或PROPAGATION_NEVER或PROPAGATION_NOT_SUPPORTED,這幾個(gè)傳播行為的含義的共同點(diǎn)之一就是:當(dāng)前方法一定以非事務(wù)的方式運(yùn)行。那么這里仍然會(huì)創(chuàng)建TransactionStatus對(duì)象,但是不會(huì)開(kāi)啟事物,相當(dāng)于一個(gè)空事務(wù)。
      • 調(diào)用prepareTransactionStatus方法返回一個(gè)TransactionStatus,和上面的startTransaction方法相比,其內(nèi)部會(huì)調(diào)用newTransactionStatus和prepareSynchronization,但不會(huì)調(diào)用doBegin方法,因此不會(huì)真正的開(kāi)啟事物。這里它的newTransaction參數(shù)為false,suspendedResources參數(shù)為null。
    @Overridepublic final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {//獲取當(dāng)前事務(wù),該方法由具體的事務(wù)管理器子類自己實(shí)現(xiàn),比如DataSourceTransactionManager、JtaTransactionManager//一般都使用DataSourceTransactionManager這個(gè)事務(wù)管理器//對(duì)于DataSourceTransactionManager這里獲取的實(shí)際上是一個(gè)數(shù)據(jù)庫(kù)的事務(wù)連接對(duì)象,即DataSourceTransactionObjectObject transaction = doGetTransaction();// Cache debug flag to avoid repeated checks.boolean debugEnabled = logger.isDebugEnabled();if (definition == null) {// Use defaults if no transaction definition given.definition = new DefaultTransactionDefinition();}// isExistingTransaction,默認(rèn)返回false,同樣被具體的事務(wù)管理器子類重寫// DataSourceTransactionManager的方法將會(huì)判斷上面獲取的DataSourceTransactionObject內(nèi)部的數(shù)據(jù)庫(kù)連接connectionHolder屬性是否不為null,// 并且是否已經(jīng)開(kāi)啟了事務(wù)。我們說(shuō)過(guò)如果當(dāng)前線程是第一次進(jìn)來(lái),那么connectionHolder就是null。if (isExistingTransaction(transaction)) {// Existing transaction found -> check propagation behavior to find out how to behave.//如果已經(jīng)存在事務(wù),那么將檢查傳播行為并進(jìn)行不同的處理,隨后返回return handleExistingTransaction(definition, transaction, debugEnabled);}//到這里表示沒(méi)有已存在的事務(wù),進(jìn)入第一個(gè)事務(wù)方法時(shí)將會(huì)走這個(gè)邏輯//設(shè)置的事務(wù)超時(shí)時(shí)間如果小于默認(rèn)超時(shí)時(shí)間(-1),將會(huì)拋出異常// Check definition settings for new transaction.if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());}//如果配置的事務(wù)的傳播行為是PROPAGATION_MANDATORY,該傳播行為的含義是://如果當(dāng)前存在事務(wù),則當(dāng)前方法加入到該事務(wù)中去,如果當(dāng)前不存在事務(wù),則當(dāng)前方法直接拋出異常。//這里就直接拋出異常。// No existing transaction found -> check propagation behavior to find out how to proceed.if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");}//否則,如果配置的事務(wù)的傳播行為是PROPAGATION_REQUIRED或者PROPAGATION_REQUIRES_NEW或者PROPAGATION_NESTED,//這幾個(gè)傳播行為的含義的共同點(diǎn)之一就是:如果當(dāng)前不存在事務(wù),就創(chuàng)建一個(gè)新事務(wù)運(yùn)行。//那么這里將開(kāi)啟一個(gè)新事物。else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {//暫停給定的事務(wù)。首先掛起事務(wù)同步,然后再委派給doSuspend模板方法。由于此前沒(méi)有事務(wù),所以參數(shù)事務(wù)為nullSuspendedResourcesHolder suspendedResources = suspend(null);if (debugEnabled) {logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);}try {boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);//開(kāi)啟一個(gè)新事務(wù)并返回DefaultTransactionStatus status = newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);doBegin(transaction, definition);prepareSynchronization(status, definition);return status;}catch (RuntimeException | Error ex) {//喚醒此前掛起的事務(wù)和資源resume(null, suspendedResources);throw ex;}}//否則,配置的事務(wù)的傳播行為就是剩下的三種:PROPAGATION_SUPPORTS或PROPAGATION_NEVER或PROPAGATION_NOT_SUPPORTED,//這幾個(gè)傳播行為的含義的共同點(diǎn)之一就是:當(dāng)前方法一定以非事務(wù)的方式運(yùn)行。else {//將會(huì)創(chuàng)建“空”事務(wù):即沒(méi)有實(shí)際的事務(wù),但是有潛在的同步性。//如果配置的事務(wù)的隔離級(jí)別不是默認(rèn)的隔離級(jí)別,那么輸出警告://雖然指定了自定義的隔離級(jí)別,但是由于未啟動(dòng)任何事物,那么隔離級(jí)別也就不會(huì)生效了// Create "empty" transaction: no actual transaction, but potentially synchronization.if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {logger.warn("Custom isolation level specified but no actual transaction initiated; " +"isolation level will effectively be ignored: " + definition);}boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);//為給定參數(shù)創(chuàng)建一個(gè)新的TransactionStatus,并在適當(dāng)時(shí)初始化事務(wù)同步,但是不會(huì)真正開(kāi)啟事務(wù)。//和startTransaction相比,其內(nèi)部會(huì)調(diào)用newTransactionStatus和prepareSynchronization,但不會(huì)調(diào)用doBegin方法return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);}}
    • doGetTransaction獲取事務(wù)連接

    返回當(dāng)前已存在的事務(wù)對(duì)象,返回的對(duì)象應(yīng)包含有關(guān)任何現(xiàn)有事務(wù)的信息,即,在事務(wù)管理器上的當(dāng)前getTransaction方法調(diào)用之前已經(jīng)啟動(dòng)的事務(wù)。因此,doGetTransaction的實(shí)現(xiàn)通常是將查找現(xiàn)有事務(wù)并將相應(yīng)的狀態(tài)存儲(chǔ)在返回的事務(wù)對(duì)象中。返回的對(duì)象通常特定于具體的事務(wù)管理器子類自己實(shí)現(xiàn)。一般都使用DataSourceTransactionManager這個(gè)事務(wù)管理器,它的doGetTransaction方法邏輯如下:

  • 創(chuàng)建一個(gè)DataSourceTransactionObject對(duì)象,由DataSourceTransactionManager用作內(nèi)部事務(wù)對(duì)象。可能會(huì)持有一個(gè)ConnectionHolder對(duì)象,還具有創(chuàng)建、回滾、釋放保存點(diǎn)的功能。
  • 設(shè)置是否允許保存點(diǎn),DataSourceTransactionManager默認(rèn)會(huì)允許,一般用于實(shí)現(xiàn)嵌套事務(wù)。
  • obtainDataSource方法用于獲取配置的數(shù)據(jù)源,就是我們自己配置的數(shù)據(jù)源,getResource用于獲取此線程在當(dāng)前數(shù)據(jù)源中已擁有JDBC連接資源持有者。如果此前沒(méi)有獲取過(guò)連接,則返回null;如果此前開(kāi)啟了過(guò)事務(wù)(外層事務(wù)),那么肯定不會(huì)獲取null。
  • 設(shè)置連接信息,newConnectionHolder屬性設(shè)置為false,這表示默認(rèn)此前已經(jīng)存在ConnectionHolder,但實(shí)際上可能并沒(méi)有,因此后面的步驟中會(huì)再次判斷該值。
  • 最后返回DataSourceTransactionObject。
  • @Override//DataSourceTransactionManagerprotected Object doGetTransaction() {//創(chuàng)建一個(gè)DataSourceTransactionObject,由DataSourceTransactionManager用作內(nèi)部事務(wù)對(duì)象。//內(nèi)部可能會(huì)持有一個(gè)ConnectionHolder對(duì)象,還具有創(chuàng)建、回滾、釋放保存點(diǎn)的功能DataSourceTransactionObject txObject = new DataSourceTransactionObject();//設(shè)置是否允許保存點(diǎn),DataSourceTransactionManager默認(rèn)會(huì)允許,用于實(shí)現(xiàn)嵌套事務(wù)txObject.setSavepointAllowed(isNestedTransactionAllowed());//obtainDataSource方法用于獲取配置的數(shù)據(jù)源,就是我們自己配置的數(shù)據(jù)源//getResource用于獲取此線程在當(dāng)前數(shù)據(jù)源中已擁有JDBC連接資源持有者ConnectionHolder//如果此前沒(méi)有獲取過(guò)連接,則返回null;如果此前開(kāi)啟了過(guò)事務(wù)(外層事務(wù)),那么肯定不會(huì)獲取nullConnectionHolder conHolder =(ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());//設(shè)置連接信息,newConnectionHolder屬性設(shè)置為false,這表示默認(rèn)此前已經(jīng)存在ConnectionHolder//但實(shí)際上可能并沒(méi)有,因此后面的步驟中會(huì)再次判斷該值txObject.setConnectionHolder(conHolder, false);return txObject;}
    • 這里也要介紹一個(gè)類TransactionSynchronizationManager事務(wù)同步管理器

      這個(gè)類比較特別,雖然它的名字帶有Transaction以及Manager,但卻不是TransactionManager體系,它沒(méi)有任何繼承樹(shù),因此它可以看作一個(gè)很特別的工具類。該類被稱為事務(wù)同步管理器。主要用于管理每一個(gè)線程當(dāng)前所使用的數(shù)據(jù)庫(kù)事務(wù)連接資源和事務(wù)同步器(TransactionSynchronization)。
      ??一個(gè)線程在當(dāng)前只能激活一個(gè)連接資源,因此如果需要綁定新的連接資源,那么需要將此前綁定的資源刪除(或者說(shuō)保存起來(lái),等新資源使用完畢之后再恢復(fù)此前的連接資源)。另外還能支持事務(wù)同步列表,事務(wù)同步必須由事務(wù)管理器通過(guò)initSynchronization()和clearSynchronization()來(lái)進(jìn)行激活和停用,使用isSynchronizationActive()檢測(cè)當(dāng)前是否具有事務(wù)同步。
      ??TransactionSynchronizationManager內(nèi)部是通過(guò)很多ThreadLocal(線程本地變量)類型的屬性來(lái)實(shí)現(xiàn)為當(dāng)前線程維護(hù)自己的資源的功能的,實(shí)現(xiàn)資源隔離。

    部分屬性:

    public abstract class TransactionSynchronizationManager {private static final Log logger = LogFactory.getLog(TransactionSynchronizationManager.class);// 事務(wù)資源// 一個(gè)ThreadLocal屬性,用于存放線程當(dāng)前使用的數(shù)據(jù)庫(kù)資源// value是一個(gè)Map<Object, Object>,key為某個(gè)數(shù)據(jù)源DataSource ,value實(shí)際上就是連接ConnectionHolderprivate static final ThreadLocal<Map<Object, Object>> resources =new NamedThreadLocal<>("Transactional resources");/*** 事務(wù)同步* <p>* 一個(gè)ThreadLocal屬性,用于存放線程當(dāng)前激活的事務(wù)同步器TransactionSynchronization* 每個(gè)線程都可以開(kāi)啟多個(gè)事物同步,用于在處理事務(wù)的各個(gè)階段進(jìn)行自定義擴(kuò)展或者回調(diào)* <p>* TransactionSynchronization的同步回調(diào)功能類似于此前學(xué)習(xí)的@TransactionalEventListener*/private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =new NamedThreadLocal<>("Transaction synchronizations");//一個(gè)ThreadLocal屬性,用于存放線程當(dāng)前的事務(wù)的名稱private static final ThreadLocal<String> currentTransactionName =new NamedThreadLocal<>("Current transaction name");//一個(gè)ThreadLocal屬性,用于存放線程當(dāng)前的事務(wù)的只讀狀態(tài)private static final ThreadLocal<Boolean> currentTransactionReadOnly =new NamedThreadLocal<>("Current transaction read-only status");//一個(gè)ThreadLocal屬性,用于存放線程當(dāng)前的當(dāng)前事務(wù)的隔離級(jí)別private static final ThreadLocal<Integer> currentTransactionIsolationLevel =new NamedThreadLocal<>("Current transaction isolation level");//一個(gè)ThreadLocal屬性,用于存放線程當(dāng)前是否開(kāi)啟了事務(wù)private static final ThreadLocal<Boolean> actualTransactionActive =new NamedThreadLocal<>("Actual transaction active");
    • obtainDataSource獲取數(shù)據(jù)源

    獲取當(dāng)前DataSourceTransactionManager實(shí)際使用的數(shù)據(jù)源,就是我們配置給事務(wù)管理器的DataSource

    /*** @return 數(shù)據(jù)源(絕不為null)*/ protected DataSource obtainDataSource() {DataSource dataSource = getDataSource();Assert.state(dataSource != null, "No DataSource set");return dataSource; } /*** 就是我們配置的數(shù)據(jù)源*/ @Nullable private DataSource dataSource; /*** 返回此事務(wù)管理器內(nèi)部的JDBC DataSource。*/ @Nullable public DataSource getDataSource() {return this.dataSource; }
    • getResource獲取已存在的連接

    TransactionSynchronizationManager的方法,該方法檢索給定key綁定到當(dāng)前線程的資源,實(shí)際上就是嘗試從resources屬性中獲綁定當(dāng)前線程的從給定數(shù)據(jù)源獲已取到的連接資源ConnectionHolder。如果此前沒(méi)有獲取過(guò)此數(shù)據(jù)源的連接,那么將會(huì)得到一個(gè)null值,即如果是第一次進(jìn)入事務(wù)方法,那么將返回null。這里resources屬性的value是一個(gè)Map<Object, Object>,這說(shuō)明一個(gè)線程可以從不同的數(shù)據(jù)源中獲取資源,但是對(duì)于同一個(gè)數(shù)據(jù)源,只能保存一個(gè)的數(shù)據(jù)源。

    public static Object getResource(Object key) {//如有必要,解開(kāi)給定的資源句柄,否則按原樣返回給定的句柄,常用于從各種代理對(duì)象中獲取原始對(duì)象Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);//真正獲取當(dāng)前綁定的資源Object value = doGetResource(actualKey);if (value != null && logger.isTraceEnabled()) {logger.trace("Retrieved value [" + value + "] for key [" + actualKey + "] bound to thread [" +Thread.currentThread().getName() + "]");}return value;}
    • isExistingTransaction是否已存在事務(wù)

    檢查是否已經(jīng)開(kāi)啟過(guò)事務(wù),默認(rèn)返回false,被具體的事務(wù)管理器子類重寫。
    DataSourceTransactionManager的邏輯很簡(jiǎn)單,判斷通過(guò)doGetTransaction方法獲取的DataSourceTransactionObject內(nèi)部的數(shù)據(jù)庫(kù)連接connectionHolder屬性是否不為null,并且是否已經(jīng)開(kāi)啟了事務(wù)。我們說(shuō)過(guò)如果當(dāng)前線程是第一次進(jìn)來(lái),那么connectionHolder就是null。

    @Overrideprotected boolean isExistingTransaction(Object transaction) {強(qiáng)轉(zhuǎn)為DataSourceTransactionObjectDataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;判斷內(nèi)部的數(shù)據(jù)庫(kù)連接connectionHolder是否不為null并且已經(jīng)開(kāi)啟了事務(wù)return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());}
    • suspend掛起事務(wù)

    掛起給定的事務(wù)。首先掛起當(dāng)前線程的事務(wù)同步回調(diào),然后再委派給doSuspend模板方法由子類來(lái)實(shí)現(xiàn)掛起當(dāng)前事務(wù),并且還會(huì)清空TransactionSynchronizationManager中保存的當(dāng)前線程的事務(wù)信息。最終將會(huì)返回會(huì)被掛起的資源只有者SuspendedResourcesHolder。如果沒(méi)有事務(wù)同步也沒(méi)有事務(wù),那么將會(huì)返回null。當(dāng)前線程第一次進(jìn)入事務(wù)方法時(shí),默認(rèn)將會(huì)返回null。

    //AbstractPlatformTransactionManagerprotected final SuspendedResourcesHolder suspend(@Nullable Object transaction) throws TransactionException {//如果當(dāng)前線程的事務(wù)同步處于活動(dòng)狀態(tài),即存在綁定的TransactionSynchronization,則返回true。//如果是第一次因?yàn)檫M(jìn)來(lái),那么自然為falseif (TransactionSynchronizationManager.isSynchronizationActive()) {//掛起當(dāng)前線程的所有事務(wù)同步回調(diào),這類似于@TransactionalEventListener,并返回"被掛起"的回調(diào)List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();try {Object suspendedResources = null;if (transaction != null) {//掛起事務(wù),由具體的子類實(shí)現(xiàn)suspendedResources = doSuspend(transaction);}//獲取當(dāng)前事務(wù)的信息,并且清空各個(gè)ThreadLocal緩存中的當(dāng)前線程的當(dāng)前事務(wù)信息(恢復(fù)為默認(rèn)值)//獲取并清空(設(shè)置為null)事物名稱String name = TransactionSynchronizationManager.getCurrentTransactionName();TransactionSynchronizationManager.setCurrentTransactionName(null);//獲取并清空(設(shè)置為false)事物只讀狀態(tài)boolean readOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();TransactionSynchronizationManager.setCurrentTransactionReadOnly(false);//獲取并清空(設(shè)置為null)事物隔離級(jí)別Integer isolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(null);//獲取并清空(設(shè)置為false)事物是否激活boolean wasActive = TransactionSynchronizationManager.isActualTransactionActive();TransactionSynchronizationManager.setActualTransactionActive(false);//將獲取的當(dāng)前事物的信息存入一個(gè)SuspendedResourcesHolder對(duì)象中返回return new SuspendedResourcesHolder(suspendedResources, suspendedSynchronizations, name, readOnly, isolationLevel, wasActive);}catch (RuntimeException | Error ex) {// doSuspend failed - original transaction is still active...doResumeSynchronization(suspendedSynchronizations);throw ex;}}//如果沒(méi)有事務(wù)同步但是開(kāi)啟了事務(wù),那么掛起事務(wù)else if (transaction != null) {// Transaction active but no synchronization active.//掛起事務(wù),由具體的子類實(shí)現(xiàn)Object suspendedResources = doSuspend(transaction);//將掛起的資源存入一個(gè)SuspendedResourcesHolder對(duì)象中返回return new SuspendedResourcesHolder(suspendedResources);}else {// Neither transaction nor synchronization active.//事務(wù)或者事務(wù)同步均未激活,返回null,什么也不干return null;}}
    • isSynchronizationActive是否激活事務(wù)同步
      ?
      TransactionSynchronizationManager的方法,用來(lái)判斷線程在當(dāng)前是否已激活事務(wù)同步TransactionSynchronization。實(shí)際上就是synchronizations屬性中是否有綁定到當(dāng)前線程的Set集合,如果有(不為null),那就說(shuō)明存在事務(wù)同步。
    /*** TransactionSynchronizationManager的屬性* <p>* 一個(gè)ThreadLocal類型的屬性,每個(gè)線程都可以開(kāi)啟事物同步,用于在處理事務(wù)的各個(gè)階段進(jìn)行自定義擴(kuò)展或者回調(diào)* TransactionSynchronization的同步回調(diào)功能類似于此前學(xué)習(xí)的@TransactionalEventListener*/ private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =new NamedThreadLocal<>("Transaction synchronizations"); /*** TransactionSynchronizationManager的方法* <p>* 判斷當(dāng)前線程的是否注冊(cè)了事務(wù)同步*/ public static boolean isSynchronizationActive() {//獲取當(dāng)前線程綁定的TransactionSynchronization,如果不為null就說(shuō)明注冊(cè)了事務(wù)同步return (synchronizations.get() != null); }
    • doSuspendSynchronization掛起事務(wù)同步
      ??
      ??該方法掛起當(dāng)前線程在TransactionSynchronizationManager的synchronize并且將屬性中為當(dāng)前線程保持的事務(wù)同步列表引用移除,最后返回被掛起的事務(wù)同步列表!
    /*** AbstractPlatformTransactionManager的方法* <p>* 掛起所有當(dāng)前同步,并停用當(dāng)前線程的事務(wù)同步。** @return 掛起的TransactionSynchronization對(duì)象的列表*/ private List<TransactionSynchronization> doSuspendSynchronization() {//獲取線程的當(dāng)前的所有事務(wù)同步列表List<TransactionSynchronization> suspendedSynchronizations =TransactionSynchronizationManager.getSynchronizations();//遍歷,依次掛起每一個(gè)事務(wù)同步for (TransactionSynchronization synchronization : suspendedSynchronizations) {synchronization.suspend();}//清除synchronizations屬性中保存的的當(dāng)前線程的當(dāng)前事務(wù)同步集合的引用TransactionSynchronizationManager.clearSynchronization();//返回被掛起的事務(wù)同步return suspendedSynchronizations; }/*** TransactionSynchronizationManager的方法* 調(diào)用該方法時(shí)一定要保證當(dāng)前線程存在事務(wù)同步,否則將拋出異常* 因此需要先調(diào)用isSynchronizationActive方法來(lái)校驗(yàn)* <p>* 返回當(dāng)前線程的所有已注冊(cè)的事務(wù)同步的無(wú)法修改的快照列表** @return 無(wú)法修改的TransactionSynchronization實(shí)例列表* @throws IllegalStateException 如果同步未激活*/ public static List<TransactionSynchronization> getSynchronizations() throws IllegalStateException {//獲取當(dāng)前線程的事務(wù)同步列表Set<TransactionSynchronization> synchs = synchronizations.get();//為null就拋出IllegalStateException異常if (synchs == null) {throw new IllegalStateException("Transaction synchronization is not active");}// 返回不可修改的快照,以避免在迭代和調(diào)用可能進(jìn)一步注冊(cè)同步的同步回調(diào)時(shí)拋出ConcurrentModificationExceptions。if (synchs.isEmpty()) {return Collections.emptyList();} else {//在獲取的之后對(duì)快照進(jìn)行排序List<TransactionSynchronization> sortedSynchs = new ArrayList<>(synchs);AnnotationAwareOrderComparator.sort(sortedSynchs);return Collections.unmodifiableList(sortedSynchs);} }/*** TransactionSynchronizationManager的方法* 調(diào)用該方法時(shí)一定要保證當(dāng)前線程存在事務(wù)同步,否則將拋出異常* 因此需要先調(diào)用isSynchronizationActive方法來(lái)校驗(yàn)* <p>* 停用當(dāng)前線程的事務(wù)同步,由事務(wù)管理器在事務(wù)清理中調(diào)用。** @throws IllegalStateException 如果同步未激活*/ public static void clearSynchronization() throws IllegalStateException {//如果沒(méi)有激活事務(wù)同步,同樣拋出異常if (!isSynchronizationActive()) {throw new IllegalStateException("Cannot deactivate transaction synchronization - not active");}logger.trace("Clearing transaction synchronization");//移除當(dāng)前線程綁定到synchronizations屬性的值synchronizations.remove(); }
    • doSuspend掛起事務(wù)

    其核心就是doSuspend方法,該方法默認(rèn)拋出異常,由子類自己實(shí)現(xiàn)!DataSourceTransactionManager重寫的方法很簡(jiǎn)單,就是將DataSourceTransactionObject中的connectionHolder設(shè)置為null,并且將給定數(shù)據(jù)源綁定到當(dāng)前線程的連接資源從TransactionSynchronizationManager的resources屬性中移除并返回,這就是DataSourceTransactionManager被掛起的連接資源,就是此前獲取的連接。從這里能夠看出,所謂的“掛起”,就是將當(dāng)前的連接從綁定的線程本地變量中移除!

    /*** DataSourceTransactionManager的方法* <p>* 掛起當(dāng)前事務(wù),返回當(dāng)前的連接資源** @param transaction 掛起事務(wù)* @return 被掛起的資源*/ @Override protected Object doSuspend(Object transaction) {DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;//將當(dāng)前的事務(wù)對(duì)象的connectionHolder設(shè)置為nulltxObject.setConnectionHolder(null);//將當(dāng)前線程的綁定的當(dāng)前數(shù)據(jù)源對(duì)應(yīng)的連接同樣移除,并且返回被移除的連接資源return TransactionSynchronizationManager.unbindResource(obtainDataSource()); }/*** TransactionSynchronizationManager的方法* <p>* 移除當(dāng)前線程中給定key綁定的資源的值** @param key 就是當(dāng)前數(shù)據(jù)源* @return 被移除的資源,就是連接*/ public static Object unbindResource(Object key) throws IllegalStateException {Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);//真正的移除指定的key對(duì)應(yīng)的連接Object value = doUnbindResource(actualKey);if (value == null) {throw new IllegalStateException("No value for key [" + actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");}return value; }/*** 事務(wù)資源*/ private static final ThreadLocal<Map<Object, Object>> resources =new NamedThreadLocal<>("Transactional resources");/*** TransactionSynchronizationManager的方法* <p>* 移除當(dāng)前線程中給定key綁定的資源的值。** @param actualKey 就是當(dāng)前數(shù)據(jù)源* @return 被移除的資源,就是連接*/ @Nullable private static Object doUnbindResource(Object actualKey) {//獲取和當(dāng)前線程綁定的數(shù)據(jù)庫(kù)資源mapMap<Object, Object> map = resources.get();if (map == null) {return null;}//從map中移除從當(dāng)前數(shù)據(jù)源對(duì)應(yīng)的連接緩存Object value = map.remove(actualKey);//如果map為空,則刪除整個(gè)ThreadLocal。if (map.isEmpty()) {resources.remove();}// Transparently suppress a ResourceHolder that was marked as void...if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {value = null;}if (value != null && logger.isTraceEnabled()) {logger.trace("Removed value [" + value + "] for key [" + actualKey + "] from thread [" +Thread.currentThread().getName() + "]");}//返回被移除的資源return value; }
    • newTransactionStatus開(kāi)啟新事物

    新建一個(gè)DefaultTransactionStatus實(shí)現(xiàn)并返回,內(nèi)部持有我們?yōu)楫?dāng)前方法配置的事務(wù)屬性或者默認(rèn)屬性,以及保存著此前掛起的其他資源。新建一個(gè)DefaultTransactionStatus實(shí)現(xiàn)并返回,內(nèi)部持有我們?yōu)楫?dāng)前方法配置的事務(wù)屬性或者默認(rèn)屬性,以及保存著此前掛起的其他資源。

    /*** AbstractPlatformTransactionManager的方法* <p>* 為給定參數(shù)新創(chuàng)建一個(gè)TransactionStatus實(shí)例,實(shí)際類型為DefaultTransactionStatus** @param definition 為當(dāng)前方法配置的事務(wù)定義* @param transaction 獲取的事務(wù)對(duì)象* @param newTransaction 是否是新事物* @param newSynchronization 是否開(kāi)啟事務(wù)同步* @param debug 是否支持debug級(jí)別的日志* @param suspendedResources 被掛起的資源,比如此前的事務(wù)同步* @return DefaultTransactionStatus對(duì)象*/ protected DefaultTransactionStatus newTransactionStatus(TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {//如果newSynchronization為true并且當(dāng)前線程沒(méi)有綁定的事務(wù)同步,那么確定開(kāi)啟新事物同步//由于此前調(diào)用了suspend方法清理了此前的事務(wù)同步,因此一般都是需要開(kāi)啟新事務(wù)同步,即為trueboolean actualNewSynchronization = newSynchronization &&!TransactionSynchronizationManager.isSynchronizationActive();//返回一個(gè)新建的DefaultTransactionStatus對(duì)象,該對(duì)象被用來(lái)表示新開(kāi)啟的事務(wù),是TransactionStatus的默認(rèn)實(shí)現(xiàn)//內(nèi)部包括了各種新開(kāi)啟的事務(wù)狀態(tài),當(dāng)然包括此前掛起的事務(wù)的資源return new DefaultTransactionStatus(transaction, newTransaction, actualNewSynchronization,definition.isReadOnly(), debug, suspendedResources); } /*DefaultTransactionStatus的屬性*/ /*** 從事務(wù)管理器獲取的內(nèi)部事務(wù)* 對(duì)于DataSourceTransactionManager來(lái)說(shuō)就是DataSourceTransactionObject*/ @Nullable private final Object transaction; /*** 是否是新事物*/ private final boolean newTransaction; /*** 是否開(kāi)啟新事務(wù)同步*/ private final boolean newSynchronization; /*** 是否開(kāi)啟新事務(wù)同步*/ private final boolean readOnly; /*** 是否支持debug日志級(jí)別*/ private final boolean debug; /*** 此前被掛起的事務(wù)資源*/ @Nullable private final Object suspendedResources; public DefaultTransactionStatus(@Nullable Object transaction, boolean newTransaction, boolean newSynchronization,boolean readOnly, boolean debug, @Nullable Object suspendedResources) {this.transaction = transaction;this.newTransaction = newTransaction;this.newSynchronization = newSynchronization;this.readOnly = readOnly;this.debug = debug;this.suspendedResources = suspendedResources; }
    • doBegin真正開(kāi)啟事務(wù)

    該方法是核心方法,當(dāng)事務(wù)管理器決定實(shí)際開(kāi)始新事務(wù)時(shí),將調(diào)用此方法。此時(shí)之前可能沒(méi)有任何事務(wù),或者先前的事務(wù)已被暫停。根據(jù)給定的事務(wù)定義TransactionDefinition,以及此前通過(guò)doGetTransaction方法返回的事務(wù)對(duì)象(也就是DataSourceTransactionObject),使用給定的語(yǔ)義開(kāi)始一個(gè)新事務(wù)。不必關(guān)心應(yīng)用傳播行為,因?yàn)槌橄笫聞?wù)管理器已經(jīng)處理了該行為。
    ??
    大概步驟為:

  • 從數(shù)據(jù)源中獲取一個(gè)新連接Connection,并且包裝為一個(gè)ConnectionHolder對(duì)象。ConnectionHolder設(shè)置為DataSourceTransactionObject事務(wù)對(duì)象的connectionHolder屬性,并且將newConnectionHolder屬性設(shè)置為true。
  • 初始化連接的各種屬性,比如隔離級(jí)別、只讀標(biāo)志等。
  • 通過(guò)con.setAutoCommit(false),設(shè)置當(dāng)前連接為手動(dòng)提交,真正開(kāi)啟事務(wù)!
  • 設(shè)置ConnectionHolder的transactionActive屬性為true,表示激活當(dāng)前連接的事務(wù)。
  • 設(shè)置超時(shí)時(shí)間。如果不是默認(rèn)超時(shí)時(shí)間-1,那么將根據(jù)設(shè)置的值和當(dāng)前時(shí)間轉(zhuǎn)換為未來(lái)的毫秒值并創(chuàng)建新Date配置給ConnectionHolder的deadline屬性,在其他數(shù)據(jù)庫(kù)操作框架操作時(shí)將會(huì)獲取該參數(shù)。
  • 如果是新連接,即newConnectionHolder屬性為true,綁定ConnectionHolder資源到TransactionSynchronizationManager的resources屬性中,就是前面說(shuō)的事務(wù)資源,key就是當(dāng)前的屬性源dataSource,value就是ConnectionHolder。
  • //開(kāi)啟新事物,并不會(huì)處理事務(wù)的傳播行為,因?yàn)閭鞑バ袨槭荢pring提供的特性,在事務(wù)管理器中就被直接處理了@Override//DataSourceTransactionManagerprotected void doBegin(Object transaction, TransactionDefinition definition) {//強(qiáng)制轉(zhuǎn)型DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;Connection con = null;try {//如果不存在事務(wù)連接資源持有者屬性,或者資源標(biāo)記為與事務(wù)同步//簡(jiǎn)單的說(shuō)就還沒(méi)有獲取連接,那么這里從數(shù)據(jù)源中獲取一個(gè)新連接//第一次進(jìn)入事務(wù)方法時(shí)默認(rèn)就會(huì)走該邏輯if (!txObject.hasConnectionHolder() ||txObject.getConnectionHolder().isSynchronizedWithTransaction()) {//從我們配置的數(shù)據(jù)源中獲取一個(gè)新連接Connection newCon = obtainDataSource().getConnection();if (logger.isDebugEnabled()) {logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");}/** 新建一個(gè)ConnectionHolder對(duì)象,其內(nèi)部保存這獲取的連接,* 將使用SimpleConnectionHandle包裝獲取的連接并且設(shè)置為connectionHandle屬性** 該ConnectionHolder被設(shè)置給txObject的connectionHolder屬性* 以及將newConnectionHolder屬性設(shè)置為true,表示是一個(gè)新連接** 到這里,事務(wù)對(duì)象就已經(jīng)獲得了一個(gè)新連接*/txObject.setConnectionHolder(new ConnectionHolder(newCon), true);}//獲取事務(wù)對(duì)象的連接持有者,將synchronizedWithTransaction設(shè)置為true,即資源標(biāo)記為與事務(wù)同步。txObject.getConnectionHolder().setSynchronizedWithTransaction(true);//獲取內(nèi)部保存的連接con = txObject.getConnectionHolder().getConnection();/** 使用給定的事務(wù)語(yǔ)義準(zhǔn)備給定的Connection,就是設(shè)置數(shù)據(jù)庫(kù)事務(wù)的隔離級(jí)別,只讀標(biāo)志屬性** 如果我們配置的隔離級(jí)別屬性是ISOLATION_DEFAULT,即采用默認(rèn)隔離級(jí)別,或者不是默認(rèn)的隔離級(jí)別但是與連接的隔離級(jí)別一致,那么將返回null* 否則將返回從連接中直接獲取的隔離級(jí)別(如果有)*/Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);//此前的隔離級(jí)別設(shè)置給事務(wù)對(duì)象的previousIsolationLevel屬性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).//如有必要,切換為手動(dòng)提交。//從Druid數(shù)據(jù)源中獲取的連接DruidPooledConnection就是默認(rèn)自動(dòng)提交,即getAutoCommit返回trueif (con.getAutoCommit()) {txObject.setMustRestoreAutoCommit(true);if (logger.isDebugEnabled()) {logger.debug("Switching JDBC Connection [" + con + "] to manual commit");}/** 如果上面判斷是自動(dòng)提交,那么切換為手動(dòng)提交,為什么呢?如果不手動(dòng)提交,* 那么一個(gè)方法中執(zhí)行多個(gè)sql語(yǔ)句時(shí)將會(huì)每執(zhí)行一個(gè)提交一次,無(wú)法實(shí)現(xiàn)事務(wù)的控制* 開(kāi)啟手動(dòng)提交就能實(shí)現(xiàn)方法級(jí)別的整體事務(wù)控制** 并且,開(kāi)啟手動(dòng)提交時(shí),將會(huì)自動(dòng)開(kāi)啟事物*/con.setAutoCommit(false);}//事務(wù)已經(jīng)開(kāi)啟,此后的sql語(yǔ)句,如果沒(méi)有手動(dòng)commit,那么將不會(huì)真正的提交給數(shù)據(jù)庫(kù)//用戶本次對(duì)數(shù)據(jù)庫(kù)開(kāi)始進(jìn)行操作到用戶執(zhí)行commit命令之間的一系列操作為一個(gè)完整的事務(wù)周期。/*** 事務(wù)開(kāi)始后立即準(zhǔn)備事務(wù)連接,主要是對(duì)于只讀事務(wù)的優(yōu)化操作(需要手動(dòng)開(kāi)啟)* 如果將"enforceReadOnly"標(biāo)志設(shè)置為true(默認(rèn)為false),并且事務(wù)定義指示只讀事務(wù),* 則默認(rèn)實(shí)現(xiàn)將執(zhí)行"SET TRANSACTION READ ONLY"這一個(gè)sql語(yǔ)句。* 請(qǐng)注意mysql只讀事務(wù)不要開(kāi)啟,oracle的只讀事務(wù)可以開(kāi)啟*/prepareTransactionalConnection(con, definition);//設(shè)置事務(wù)ConnectionHolder的transactionActive屬性為true,表示激活當(dāng)前連接的事務(wù)//此前判斷是否有開(kāi)啟事務(wù)的isExistingTransaction方法就會(huì)判斷這個(gè)屬性txObject.getConnectionHolder().setTransactionActive(true);//設(shè)置實(shí)際超時(shí)時(shí)間int timeout = determineTimeout(definition);//如果不是默認(rèn)超時(shí)時(shí)間-1,那么將if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {//那么設(shè)置超時(shí)時(shí)間,實(shí)際上就是根據(jù)設(shè)置的值和當(dāng)前時(shí)間轉(zhuǎn)換為未來(lái)的毫秒值并創(chuàng)建新Date配置給deadline屬性//在其他數(shù)據(jù)庫(kù)操作框架操作時(shí)將會(huì)獲取該參數(shù)txObject.getConnectionHolder().setTimeoutInSeconds(timeout);}// Bind the connection holder to the thread.//如果是新的連接持有者,即newConnectionHolder屬性為trueif (txObject.isNewConnectionHolder()) {//綁定ConnectionHolder資源到TransactionSynchronizationManager的resources屬性中//key就是當(dāng)前的屬性源,value就是ConnectionHolderTransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());}}catch (Throwable ex) {//如果是新連接,那么釋放鏈接if (txObject.isNewConnectionHolder()) {DataSourceUtils.releaseConnection(con, obtainDataSource());txObject.setConnectionHolder(null, false);}throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);}}
    • prepareConnectionForTransaction準(zhǔn)備事務(wù)連接

    使用給定的事務(wù)語(yǔ)義準(zhǔn)備給定的Connection,就是將我們?cè)O(shè)置的隔離級(jí)別isolationLevel,只讀標(biāo)志readOnly屬性賦給當(dāng)前事務(wù)連接。如果我們配置的隔離級(jí)別屬性是ISOLATION_DEFAULT,即采用默認(rèn)隔離級(jí)別,或者不是默認(rèn)的隔離級(jí)別但是與連接的隔離級(jí)別一致,那么將返回null,否則將設(shè)置連接的隔離級(jí)別為指定的級(jí)別,并且返回從連接中獲取的隔離級(jí)別(如果有)。

    /*** DataSourceUtils的方法* <p>* 使用給定的事務(wù)語(yǔ)義準(zhǔn)備給定的Connection。** @param con 需要準(zhǔn)備的連接* @param definition 適用的事務(wù)定義* @return 連接先前的隔離級(jí)別,可能為null*/ @Nullable public static Integer prepareConnectionForTransaction(Connection con, @Nullable TransactionDefinition definition)throws SQLException {Assert.notNull(con, "No Connection specified");boolean debugEnabled = logger.isDebugEnabled();// 設(shè)置只讀標(biāo)志。if (definition != null && definition.isReadOnly()) {try {if (debugEnabled) {logger.debug("Setting JDBC Connection [" + con + "] read-only");}//設(shè)置連接只讀屬性con.setReadOnly(true);} catch (SQLException | RuntimeException ex) {Throwable exToCheck = ex;while (exToCheck != null) {if (exToCheck.getClass().getSimpleName().contains("Timeout")) {// Assume it's a connection timeout that would otherwise get lost: e.g. from JDBC 4.0throw ex;}exToCheck = exToCheck.getCause();}// "read-only not supported" SQLException -> ignore, it's just a hint anywaylogger.debug("Could not set JDBC Connection read-only", ex);}}// 應(yīng)用特定的隔離級(jí)別(如果有)。Integer previousIsolationLevel = null;//如果存在隔離級(jí)別并且不等于默認(rèn)配置,即不等于ISOLATION_DEFAULT(該級(jí)別的意思是使用數(shù)據(jù)庫(kù)的默認(rèn)級(jí)別)if (definition != null && definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {if (debugEnabled) {logger.debug("Changing isolation level of JDBC Connection [" + con + "] to " +definition.getIsolationLevel());}//獲取當(dāng)前連接的隔離級(jí)別int currentIsolation = con.getTransactionIsolation();//如果手動(dòng)設(shè)置的隔離級(jí)別不等于連接的隔離級(jí)別if (currentIsolation != definition.getIsolationLevel()) {//記錄連接的隔離級(jí)別previousIsolationLevel = currentIsolation;//連接的隔離級(jí)別手動(dòng)設(shè)置為我們配置的隔離級(jí)別con.setTransactionIsolation(definition.getIsolationLevel());}}//返回此前的連接的隔離級(jí)別,可能為nullreturn previousIsolationLevel; }
    • prepareTransactionalConnection優(yōu)化只讀事務(wù)
      ??事務(wù)開(kāi)始后立即準(zhǔn)備事務(wù)連接,主要是對(duì)于只讀事務(wù)的優(yōu)化操作(需要手動(dòng)開(kāi)啟)。如果將事務(wù)管理器的"enforceReadOnly"標(biāo)志設(shè)置為true(默認(rèn)為false),并且事務(wù)定義指示只讀事務(wù),則默認(rèn)實(shí)現(xiàn)將執(zhí)行"SET TRANSACTION READ ONLY"這一個(gè)sql語(yǔ)句。
      ??"SET TRANSACTION READ ONLY"這個(gè)sql的意思就是告訴數(shù)據(jù)庫(kù),此事務(wù)中的后續(xù)sql語(yǔ)句將只有查詢操作,不能進(jìn)行DML操作。在"SET TRANSACTION READ ONLY"之后的查詢語(yǔ)句將不會(huì)查詢到該事物期間提交的內(nèi)容,只能查詢到事務(wù)開(kāi)始之前提交的內(nèi)容,相當(dāng)于查詢一個(gè)快照。進(jìn)行只讀事務(wù)設(shè)置之后,將有效減輕數(shù)據(jù)庫(kù)壓力。對(duì)于同一個(gè)表進(jìn)行更新操作時(shí),只讀事務(wù)不會(huì)被阻塞,可以正常的執(zhí)行查詢操作,在只讀事務(wù)操作期間也不會(huì)影響其他事務(wù)!
    /*** DataSourceTransactionManager的方法* 如果將"enforceReadOnly"標(biāo)志設(shè)置為true,并且事務(wù)定義指示只讀事務(wù),* 則默認(rèn)實(shí)現(xiàn)將執(zhí)行"SET TRANSACTION READ ONLY"sql語(yǔ)句。** @param con 當(dāng)前連接* @param definition 為當(dāng)前方法配置的事務(wù)定義*/ protected void prepareTransactionalConnection(Connection con, TransactionDefinition definition)throws SQLException {//如果將"enforceReadOnly"標(biāo)志設(shè)置為true,并且事務(wù)定義指示只讀事務(wù)if (isEnforceReadOnly() && definition.isReadOnly()) {//那么獲取Statement,并且執(zhí)行"SET TRANSACTION READ ONLY"sql語(yǔ)句try (Statement stmt = con.createStatement()) {stmt.executeUpdate("SET TRANSACTION READ ONLY");}} }/*** DataSourceTransactionManager的屬性* <p>* 表示是否通過(guò)對(duì)事務(wù)連接顯式執(zhí)行sql語(yǔ)句強(qiáng)制執(zhí)行事務(wù)的只讀性質(zhì),默認(rèn)為false*/ private boolean enforceReadOnly = false;/*** 返回是否通過(guò)對(duì)事務(wù)連接顯式執(zhí)行sql語(yǔ)句強(qiáng)制執(zhí)行事務(wù)的只讀性質(zhì)。*/ public boolean isEnforceReadOnly() {return this.enforceReadOnly; }

    上面說(shuō)了這么多好處,很遺憾的是DataSourceTransactionManager的enforceReadOnly屬性默認(rèn)為false,并且大部分開(kāi)發(fā)者也不知道這個(gè)優(yōu)化,因此大多數(shù)情況下并不會(huì)執(zhí)行該sql語(yǔ)句,即不會(huì)進(jìn)行優(yōu)化。如果要開(kāi)啟,那么可以這么設(shè)置:

    /*** 配置DataSourceTransactionManager* 用于管理某一個(gè)數(shù)據(jù)庫(kù)的事務(wù)*/ @Bean public DataSourceTransactionManager transactionManager() {DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager(druidDataSource());//設(shè)置只讀事務(wù)優(yōu)化dataSourceTransactionManager.setEnforceReadOnly(true);//傳入一個(gè)數(shù)據(jù)源return dataSourceTransactionManager; }

    當(dāng)然如果你真的這么開(kāi)啟了,并且你通過(guò)@Transactional注解設(shè)置了某個(gè)方法的事務(wù)的readOnly屬性為true,那么確實(shí)會(huì)執(zhí)行該方法,但是你講將會(huì)收到一個(gè)異常:“Connection is read-only. Queries leading to data modification are not allowed”。原因是什么呢?很簡(jiǎn)單,在前面的prepareConnectionForTransaction方法中,連接被設(shè)置為只讀,然而在隨后的prepareTransactionalConnection方法中,執(zhí)行該sql語(yǔ)句的卻是executeUpdate方法,自然會(huì)拋出異常!所以說(shuō),這個(gè)優(yōu)化還不能隨便開(kāi)?;蛘哒f(shuō),是因?yàn)椴煌臄?shù)據(jù)庫(kù)對(duì)于Spring的readOnly屬性的支持是不一樣的,mysql支持Spring的readOnly參數(shù),即支持JDBC的con.setReadOnly(true),因此就沒(méi)必要再設(shè)置enforceReadOnly為true,而oracle則僅支持在Oracle server的設(shè)置而非JDBC驅(qū)動(dòng)的配置,因此不支持con.setReadOnly(true),所以實(shí)際上Spring的readOnly配置對(duì)于Oracle無(wú)效,所以O(shè)racle數(shù)據(jù)庫(kù)可以開(kāi)啟此優(yōu)化,mysql則不必要。

    • determineTimeout確定超時(shí)時(shí)間

    確定給定事務(wù)定義的實(shí)際超時(shí)時(shí)間。如果事務(wù)定義未指定非默認(rèn)值,則將使用默認(rèn)超時(shí)。

    /*** AbstractPlatformTransactionManager的方法* <p>* 確定給定事務(wù)定義的實(shí)際超時(shí)時(shí)間。* 如果事務(wù)定義未指定非默認(rèn)值,則將使用默認(rèn)超時(shí)。** @param definition 事務(wù)定義* @return 實(shí)際使用的超時(shí)時(shí)間*/ protected int determineTimeout(TransactionDefinition definition) {//如果不是默認(rèn)超時(shí)時(shí)間,那么使用指定的事件if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {return definition.getTimeout();}//否則使用默認(rèn)超時(shí)return getDefaultTimeout(); }/*** AbstractPlatformTransactionManager的屬性* <p>* 默認(rèn)超時(shí)時(shí)間(秒),默認(rèn)值為-1,表示使用基礎(chǔ)事務(wù)系統(tǒng)的默認(rèn)超時(shí);*/ private int defaultTimeout = TransactionDefinition.TIMEOUT_DEFAULT;public final int getDefaultTimeout() {return this.defaultTimeout; }
    • setTimeoutInSeconds設(shè)置超時(shí)deadline

    這里實(shí)際上就是根據(jù)設(shè)置的值和當(dāng)前時(shí)間轉(zhuǎn)換為未來(lái)的毫秒值并創(chuàng)建新Date配置給deadline屬性,在其他數(shù)據(jù)庫(kù)操作框架具體操作時(shí)將會(huì)獲取并應(yīng)用該參數(shù)。比如mybatis,在執(zhí)行sql之前會(huì)獲取到超時(shí)時(shí)間,計(jì)算之后會(huì)通過(guò)Statement.setQueryTimeout方法來(lái)設(shè)置,也就是說(shuō)這個(gè)超時(shí)時(shí)間是執(zhí)行sql之前的代碼執(zhí)行時(shí)間+sql執(zhí)行時(shí)間,如果執(zhí)行時(shí)間超過(guò)了設(shè)置時(shí)間就會(huì)拋出異常,這個(gè)異常就會(huì)被spring事務(wù)切面捕獲到最終導(dǎo)致事務(wù)回滾,而如果在sql執(zhí)行完畢之后的方法處理時(shí)間超過(guò)了這個(gè)超時(shí)時(shí)間,那么是不會(huì)進(jìn)行回滾的,事務(wù)將會(huì)正常提交。

    /*** ConnectionHolder的父類ResourceHolderSupport的方法* <p>* 設(shè)置此對(duì)象的超時(shí)(以秒為單位)。** @param seconds 到期前的秒數(shù)*/ public void setTimeoutInSeconds(int seconds) {setTimeoutInMillis(seconds * 1000L); }/*** ConnectionHolder的父類ResourceHolderSupport的屬性*/ @Nullable private Date deadline;/*** 設(shè)置此對(duì)象的超時(shí)(以毫秒為單位)。** @param millis 到期前的毫秒數(shù)*/ public void setTimeoutInMillis(long millis) {//根據(jù)當(dāng)前時(shí)間和超時(shí)時(shí)間計(jì)算出到期的Datethis.deadline = new Date(System.currentTimeMillis() + millis); }
    • bindResource綁定資源到resources

    對(duì)于新獲取的連接資源會(huì)被綁定到TransactionSynchronizationManager的resources線程本地變量屬性中(resources我們?cè)诖饲熬鸵?jiàn)過(guò)了)。key就是當(dāng)前的屬性源DataSource,value就是ConnectionHolder。

    /*** 事務(wù)資源*/ private static final ThreadLocal<Map<Object, Object>> resources =new NamedThreadLocal<>("Transactional resources");/*** TransactionSynchronizationManager的方法* <p>* 將給定key的給定資源value綁定到當(dāng)前線程。* 對(duì)于DataSourceTransactionManager,key就是DataSource實(shí)例,value就是ConnectionHolder** @param key 將值綁定到的鍵(通常是資源工廠,比如dataSource)* @param value 要綁定的值(通常是活動(dòng)資源對(duì)象,比如數(shù)據(jù)庫(kù)連接)* @throws IllegalStateException 如果已經(jīng)有綁定到線程的值*/ public static void bindResource(Object key, Object value) throws IllegalStateException {Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);Assert.notNull(value, "Value must not be null");//獲取當(dāng)前線程的本地資源mapMap<Object, Object> map = resources.get();//如果找不到,則設(shè)置一個(gè)Mapif (map == null) {map = new HashMap<>();resources.set(map);}//將actualKey和value存入map中,返回舊的valueObject oldValue = map.put(actualKey, value);// Transparently suppress a ResourceHolder that was marked as void...if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) {oldValue = null;}//如果已經(jīng)有綁定到線程的當(dāng)前key的值,則拋出異常if (oldValue != null) {throw new IllegalStateException("Already value [" + oldValue + "] for key [" +actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");}if (logger.isTraceEnabled()) {logger.trace("Bound value [" + value + "] for key [" + actualKey + "] to thread [" +Thread.currentThread().getName() + "]");} }
    • prepareSynchronization準(zhǔn)備事務(wù)同步
      ??
      該方法通常用在doBegin開(kāi)啟新事物之后,用于準(zhǔn)備事務(wù)同步,就是將當(dāng)前事務(wù)的一系列屬性綁定到TransactionSynchronizationManager的對(duì)應(yīng)的線程本地變量中。
    /*** AbstractPlatformTransactionManager的方法* <p>* 適當(dāng)?shù)爻跏蓟聞?wù)同步。*/ protected void prepareSynchronization(DefaultTransactionStatus status, TransactionDefinition definition) {//是否是新同步,在真正的開(kāi)啟新事務(wù)的時(shí)候(比如第一次進(jìn)入事務(wù)方法或者傳播行為是REQUIRES_NEW),一般都是trueif (status.isNewSynchronization()) {//配置當(dāng)前事務(wù)的一系列屬性//是否具有事務(wù)TransactionSynchronizationManager.setActualTransactionActive(status.hasTransaction());//傳播行為TransactionSynchronizationManager.setCurrentTransactionIsolationLevel(definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT ?definition.getIsolationLevel() : null);//只讀狀態(tài)TransactionSynchronizationManager.setCurrentTransactionReadOnly(definition.isReadOnly());//事務(wù)名TransactionSynchronizationManager.setCurrentTransactionName(definition.getName());//初始化同步TransactionSynchronizationManager.initSynchronization();} }private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =new NamedThreadLocal<>("Transaction synchronizations");/*** TransactionSynchronizationManager的方法* <p>* 激活當(dāng)前線程的事務(wù)同步。由事務(wù)管理器在事務(wù)開(kāi)始時(shí)調(diào)用。** @throws IllegalStateException 如果同步已處于活動(dòng)狀態(tài)*/ public static void initSynchronization() throws IllegalStateException {//如果同步已處于活動(dòng)狀態(tài),即synchronizations保存的線程本地變量不為null,則拋出異常if (isSynchronizationActive()) {throw new IllegalStateException("Cannot activate transaction synchronization - already active");}logger.trace("Initializing transaction synchronization");//否則就為當(dāng)前初始化一個(gè)線程本地變量,這是一個(gè)空的LinkedHashSet//雖然沒(méi)有任何的TransactionSynchronization,但是已經(jīng)不為null了synchronizations.set(new LinkedHashSet<>()); }
    • prepareTransactionStatus準(zhǔn)備事務(wù)狀態(tài)
    • prepareTransactionStatus方法和上面的startTransaction方法相比,其內(nèi)部會(huì)調(diào)用newTransactionStatus和prepareSynchronization,但不會(huì)調(diào)用doBegin方法,因此不會(huì)真正的開(kāi)啟事物。返回的TransactionStatus,其內(nèi)部保存了其他的資源,比如被掛起的事務(wù)信息。
    • 如果是第一次進(jìn)入事務(wù)方法,即當(dāng)前方法是最外層事務(wù)方法,并且傳播行為是PROPAGATION_SUPPORTS或PROPAGATION_NEVER或PROPAGATION_NOT_SUPPORTED,那么會(huì)調(diào)用該方法,它的newTransaction參數(shù)為false,suspendedResources參數(shù)為null。即這些傳播行為都不會(huì)真正的開(kāi)啟數(shù)據(jù)庫(kù)級(jí)別的事務(wù)(不會(huì)獲取新的連接)。
    • 如果是已存在外層事務(wù),即當(dāng)前方法是內(nèi)層事務(wù)方法,并且傳播行為是PROPAGATION_NOT_SUPPORTED或者PROPAGATION_NESTED或者PROPAGATION_SUPPORTS或者PROPAGATION_REQUIRED或者PROPAGATION_MANDATORY,那么也有可能調(diào)用這個(gè)方法,它的newTransaction參數(shù)為false,suspendedResources參數(shù)為被掛起的外層事務(wù)資源。即這些傳播行為都不會(huì)真正的開(kāi)啟數(shù)據(jù)庫(kù)級(jí)別的事務(wù)(不會(huì)獲取新的連接,對(duì)于普通事物來(lái)說(shuō))。
    /**1. 根據(jù)給定參數(shù)創(chuàng)建一個(gè)新的TransactionStatus,并在適當(dāng)時(shí)初始化事務(wù)同步,不會(huì)真正開(kāi)啟新事物。2. 3. @param definition 為當(dāng)前方法設(shè)置的事務(wù)定義4. @param transaction 當(dāng)前已存在的事務(wù)5. @param newTransaction 是否是新事物,如果是外層事務(wù)方法,則為true,如果是內(nèi)層方法則為false6. @param newSynchronization 是否是新事務(wù)同步7. @param debug 是否支持debug日志8. @param suspendedResources 被掛起的資源9. @return 一個(gè)TransactionStatus的實(shí)現(xiàn)*/ protected final DefaultTransactionStatus prepareTransactionStatus(TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {//通過(guò)newTransactionStatus創(chuàng)建一個(gè)DefaultTransactionStatusDefaultTransactionStatus status = newTransactionStatus(definition, transaction, newTransaction, newSynchronization, debug, suspendedResources);//中間缺少了doBegin真正開(kāi)啟事務(wù)的訪法,所以僅僅是創(chuàng)建了一個(gè)簡(jiǎn)單的TransactionStatus//包存了一些其他信息,比如被掛起的資源信息//準(zhǔn)備事務(wù)同步prepareSynchronization(status, definition);return status;

    }

    • 如果當(dāng)前已存在事務(wù),則handleExistingTransaction處理已存在事務(wù)
      ??
      如果進(jìn)入事務(wù)切面之后,獲取到了已存在的連接并且開(kāi)啟了事務(wù)(通過(guò)isExistingTransaction方法判斷),那么將會(huì)執(zhí)行handleExistingTransaction方法執(zhí)行已存在事務(wù)時(shí)的邏輯,并返回一個(gè)TransactionStatus。該方法同樣將會(huì)根據(jù)此事務(wù)切面設(shè)置的事務(wù)傳播行為走不同的執(zhí)行流程,比如加入當(dāng)前事務(wù)、新建事務(wù)、拋出異常等等邏輯。
      ??大概邏輯是:
  • 如果當(dāng)前配置的傳播行為是PROPAGATION_NEVER,該行為的特點(diǎn)是:當(dāng)前方法一定以非事務(wù)的方式運(yùn)行,并且如果當(dāng)前存在事務(wù),則直接拋出異常,所以這里由于存在外部事務(wù),那么直接拋出異常:“Existing
    transaction found for transaction marked with propagation ‘never’”。
  • 如果當(dāng)前配置的傳播行為是PROPAGATION_NOT_SUPPORTED,該行為的特點(diǎn)是:當(dāng)前方法一定以非事務(wù)的方式運(yùn)行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起,直到當(dāng)前方法執(zhí)行完畢,才恢復(fù)外層事務(wù)。
      • 首先調(diào)用suspend方法掛起外層事務(wù),返回被掛起的資源。由于存在外層事務(wù),所以這里的參數(shù)就是獲取的外層事務(wù)參數(shù)。
      • 隨后調(diào)用prepareTransactionStatus方法返回一個(gè)新的TransactionStatus,并在適當(dāng)時(shí)初始化事務(wù)同步。同樣,該方法和上面的startTransaction方法相比,其內(nèi)部會(huì)調(diào)用newTransactionStatus和prepareSynchronization,但不會(huì)調(diào)用doBegin方法,因此不會(huì)真正的開(kāi)啟事物。這里它的newTransaction參數(shù)為false,transaction參數(shù)為null,suspendedResources參數(shù)為被掛起的外層事務(wù)資源。
  • 如果當(dāng)前配置的傳播行為是PROPAGATION_REQUIRES_NEW,該行為的特點(diǎn)是:當(dāng)前方法開(kāi)啟一個(gè)新事物獨(dú)立運(yùn)行,從不參與外部的現(xiàn)有事務(wù)。則當(dāng)內(nèi)部事務(wù)開(kāi)始執(zhí)行時(shí),外部事務(wù)(如果存在)將被掛起,內(nèi)務(wù)事務(wù)結(jié)束時(shí),外部事務(wù)將繼續(xù)執(zhí)行。
      • 首先調(diào)用suspend方法掛起外層事務(wù),返回被掛起的資源。由于存在外層事務(wù),所以這里的參數(shù)就是獲取的外層事務(wù)參數(shù)。
      • 隨后調(diào)用startTransaction方法真正的開(kāi)啟一個(gè)數(shù)據(jù)庫(kù)級(jí)別的事務(wù)(將會(huì)獲取新的連接開(kāi)啟一個(gè)新事物,舊的連接和事務(wù)則在上面的suspend方法中被掛起保存)。
  • 如果當(dāng)前配置的傳播行為是PROPAGATION_NESTED,該行為的特點(diǎn)是:
    如果當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)新“事務(wù)”作為當(dāng)前事務(wù)的嵌套事務(wù)來(lái)運(yùn)行;如果當(dāng)前沒(méi)有事務(wù),則等價(jià)于PROPAGATION_REQUIRED,即會(huì)新建一個(gè)事務(wù)運(yùn)行。
      • 調(diào)用isNestedTransactionAllowed方法判斷是否允許PROPAGATION_NESTED行為,默認(rèn)不允許,但是DataSourceTransactionManager重寫為允許。不允許就拋出異常:“Transaction manager does not allow nested transactions……”。
      • 調(diào)用useSavepointForNestedTransaction方法判斷是否對(duì)“嵌套事務(wù)”使用保存點(diǎn)Savepoint來(lái)實(shí)現(xiàn):
        • 如果允許,那么首先調(diào)用prepareTransactionStatus方法返回一個(gè)新的TransactionStatus,并在適當(dāng)時(shí)初始化事務(wù)同步。這里它的newTransaction參數(shù)為false,transaction參數(shù)為外層事務(wù),suspendedResources參數(shù)為null,newSynchronization參數(shù)為false。隨后調(diào)用createAndHoldSavepoint創(chuàng)建保存點(diǎn),將使用數(shù)據(jù)庫(kù)的保存點(diǎn)的特性來(lái)實(shí)現(xiàn)“嵌套事務(wù)”,這是用語(yǔ)大部分普通事務(wù)。
        • 否則將調(diào)用startTransaction方法通過(guò)在外層事務(wù)中嵌套的begin和commit/rollback調(diào)用來(lái)開(kāi)啟真正的嵌套事務(wù),不過(guò)通常僅用于JTA:如果存在預(yù)先存在的JTA事務(wù),則可以在此處激活Spring同步。
  • 剩下的傳播行為就是PROPAGATION_SUPPORTS或者PROPAGATION_REQUIRED或者PROPAGATION_MANDATORY,如果是這些行為,那么它們的一個(gè)共同的特性就是:參與到當(dāng)前事務(wù)中去,也是默認(rèn)傳播行為的邏輯。
      • 那么這里同樣調(diào)用prepareTransactionStatus方法,這里它的newTransaction參數(shù)為false,transaction參數(shù)為外層事務(wù),suspendedResources參數(shù)為null。

    從源碼中我們能夠看到,如果傳播行為是PROPAGATION_NESTED:

  • 對(duì)于普通事務(wù)(比如DataSourceTransactionManager處理的事務(wù)),它的“嵌套事務(wù)”是通過(guò)SavePoint保存點(diǎn)來(lái)實(shí)現(xiàn)的,實(shí)際上就是同一個(gè)事務(wù)。基于保存點(diǎn)的特性,此時(shí),“內(nèi)層事務(wù)”依賴“外層事物”:層事務(wù)操作失敗時(shí)只是自身回到到保存點(diǎn)的位置,不會(huì)引起外層事務(wù)的回滾,而外層事務(wù)因失敗而回滾時(shí),內(nèi)層事務(wù)所做的所有動(dòng)作也會(huì)回滾。在提交時(shí),在外層事務(wù)提交之后內(nèi)層事務(wù)才能提交,僅需要提交外層事務(wù)即可。由于實(shí)際上只有一個(gè)物理事務(wù),那么內(nèi)層事務(wù)會(huì)繼承外層外層事務(wù)的隔離級(jí)別和超時(shí)設(shè)置等屬性。
  • 對(duì)于JTA事務(wù)(分布式事務(wù)),我們能看到是調(diào)用了startTransaction方法,因此將會(huì)在原本的事務(wù)中通過(guò)嵌套的begin和commit/rollback調(diào)用來(lái)開(kāi)啟的嵌套事務(wù),這是真正的嵌套事務(wù)。
  • /*** AbstractPlatformTransactionManager的方法* <p>* 根據(jù)現(xiàn)有事務(wù)創(chuàng)建一個(gè)TransactionStatus,處理事務(wù)的傳播行為** @param definition 當(dāng)前事務(wù)定義* @param transaction 事物對(duì)象,內(nèi)部包含此前的事務(wù)信息* @param debugEnabled 日志級(jí)別支持* @return 事務(wù)狀態(tài)對(duì)象*/ private TransactionStatus handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled)throws TransactionException {/** 1 如果當(dāng)前配置的傳播行為是PROPAGATION_NEVER,該行為的特點(diǎn)是:* 當(dāng)前方法一定以非事務(wù)的方式運(yùn)行,并且如果當(dāng)前存在事務(wù),則直接拋出異常* 所以這里直接拋出異常*/if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {throw new IllegalTransactionStateException("Existing transaction found for transaction marked with propagation 'never'");}/** 2 如果當(dāng)前配置的傳播行為是PROPAGATION_NOT_SUPPORTED,該行為的特點(diǎn)是:* 當(dāng)前方法一定以非事務(wù)的方式運(yùn)行,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起,直到當(dāng)前方法執(zhí)行完畢,才恢復(fù)外層事務(wù)。*/if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {if (debugEnabled) {logger.debug("Suspending current transaction");}//那么這里掛起外層事務(wù)Object suspendedResources = suspend(transaction);//判斷是否需要進(jìn)行新同步,默認(rèn)都是需要的boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);//為給定參數(shù)創(chuàng)建一個(gè)新的TransactionStatus,并在適當(dāng)時(shí)初始化事務(wù)同步。//這里的第二個(gè)參數(shù)事務(wù)屬性為null,表示當(dāng)前方法以非事務(wù)的方式執(zhí)行return prepareTransactionStatus(definition, null, false, newSynchronization, debugEnabled, suspendedResources);}/** 3 如果當(dāng)前配置的傳播行為是PROPAGATION_REQUIRES_NEW,該行為的特點(diǎn)是:* 當(dāng)前方法開(kāi)啟一個(gè)新事物獨(dú)立運(yùn)行,從不參與外部的現(xiàn)有事務(wù)。則當(dāng)內(nèi)部事務(wù)開(kāi)始執(zhí)行時(shí),* 外部事務(wù)(如果存在)將被掛起,內(nèi)務(wù)事務(wù)結(jié)束時(shí),外部事務(wù)將繼續(xù)執(zhí)行。*/if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {if (debugEnabled) {logger.debug("Suspending current transaction, creating new transaction with name [" +definition.getName() + "]");}//那么這里掛起外層事務(wù),返回被掛起的資源SuspendedResourcesHolder suspendedResources = suspend(transaction);try {//開(kāi)啟一個(gè)新事務(wù)并返回return startTransaction(definition, transaction, debugEnabled, suspendedResources);} catch (RuntimeException | Error beginEx) {//恢復(fù)被掛起的事務(wù)resumeAfterBeginException(transaction, suspendedResources, beginEx);throw beginEx;}}/** 4 如果當(dāng)前配置的傳播行為是PROPAGATION_NESTED,該行為的特點(diǎn)是:* 如果當(dāng)前存在事務(wù),則創(chuàng)建一個(gè)新“事務(wù)”作為當(dāng)前事務(wù)的嵌套事務(wù)來(lái)運(yùn)行;* 如果當(dāng)前沒(méi)有事務(wù),則等價(jià)于PROPAGATION_REQUIRED,即會(huì)新建一個(gè)事務(wù)運(yùn)行。**/if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {//判斷是否允許PROPAGATION_NESTED行為,默認(rèn)不允許,但是DataSourceTransactionManager重寫為為允許if (!isNestedTransactionAllowed()) {throw new NestedTransactionNotSupportedException("Transaction manager does not allow nested transactions by default - " +"specify 'nestedTransactionAllowed' property with value 'true'");}if (debugEnabled) {logger.debug("Creating nested transaction with name [" + definition.getName() + "]");}//返回是否對(duì)嵌套事務(wù)使用保存點(diǎn),默認(rèn)true,JtaTransactionManager設(shè)置為false//PROPAGATION_NESTED就是通過(guò)Savepoint保存點(diǎn)來(lái)實(shí)現(xiàn)的if (useSavepointForNestedTransaction()) {//并沒(méi)有掛起當(dāng)前事務(wù),創(chuàng)建TransactionStatus,transaction參數(shù)就是當(dāng)前事務(wù)DefaultTransactionStatus status =prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);/** 通過(guò)TransactionStatus實(shí)現(xiàn)的SavepointManager API在現(xiàn)有的Spring管理的事務(wù)中創(chuàng)建保存點(diǎn),通常使用JDBC 3.0保存點(diǎn)。*/status.createAndHoldSavepoint();return status;} else {// 通過(guò)在事務(wù)中嵌套的begin和commit / rollback調(diào)用開(kāi)啟的嵌套事務(wù)。// 通常僅用于JTA:如果存在預(yù)先存在的JTA事務(wù),則可以在此處激活Spring同步。return startTransaction(definition, transaction, debugEnabled, null);}}//剩下的傳播行為就是PROPAGATION_SUPPORTS或者PROPAGATION_REQUIRED或者PROPAGATION_MANDATORY。if (debugEnabled) {logger.debug("Participating in existing transaction");}//是否在參與現(xiàn)有事務(wù)之前進(jìn)行驗(yàn)證,默認(rèn)falseif (isValidateExistingTransaction()) {if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {Constants isoConstants = DefaultTransactionDefinition.constants;throw new IllegalTransactionStateException("Participating transaction with definition [" +definition + "] specifies isolation level which is incompatible with existing transaction: " +(currentIsolationLevel != null ?isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :"(unknown)"));}}if (!definition.isReadOnly()) {if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {throw new IllegalTransactionStateException("Participating transaction with definition [" +definition + "] is not marked as read-only but existing transaction is");}}}//并沒(méi)有掛起當(dāng)前事務(wù),而是直接參與到當(dāng)前事務(wù)中去,transaction參數(shù)就是當(dāng)前的事務(wù)boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null); }
    • createAndHoldSavepoint創(chuàng)建保存點(diǎn)

    該方法很簡(jiǎn)單,最終會(huì)調(diào)用當(dāng)前的JDBC連接Connection的setSavepoint方法創(chuàng)建一個(gè)保存點(diǎn),并且被設(shè)置給當(dāng)前TransactionStatus對(duì)象的savepoint屬性。

    /*** AbstractTransactionStatus的方法* <p>* 創(chuàng)建一個(gè)保存點(diǎn)并將其保存在事務(wù)中。** @throws NestedTransactionNotSupportedException 如果基礎(chǔ)事務(wù)不支持保存點(diǎn)*/ public void createAndHoldSavepoint() throws TransactionException {setSavepoint(getSavepointManager().createSavepoint()); } /*** AbstractTransactionStatus的屬性*/ @Nullable private Object savepoint;/*** AbstractTransactionStatus的方法* <p>* 設(shè)置此事務(wù)的保存點(diǎn),對(duì)PROPAGATION_NESTED有用。*/ protected void setSavepoint(@Nullable Object savepoint) {this.savepoint = savepoint; }

    getSavepointManager獲取獲取保存點(diǎn)管理器,實(shí)際上創(chuàng)建的內(nèi)部事務(wù)對(duì)象都是SavepointManager接口的實(shí)現(xiàn),具有獲取保存點(diǎn)的方法!因此返回的實(shí)際上就是內(nèi)部的事務(wù)對(duì)象,對(duì)于DataSourceTransactionManager來(lái)說(shuō)創(chuàng)建的內(nèi)部事務(wù)就是DataSourceTransactionObject。

    /*** DefaultTransactionStatus的屬性* <p>* 獲取基礎(chǔ)事務(wù)對(duì)象的SavepointManager,實(shí)際上就是獲取的內(nèi)部事務(wù)對(duì)象*/ @Nullable private final Object transaction;/*** DefaultTransactionStatus的方法* <p>* 獲取基礎(chǔ)事務(wù)對(duì)象的SavepointManager,實(shí)際上就是獲取的內(nèi)部事務(wù)對(duì)象*/ @Override protected SavepointManager getSavepointManager() {//獲取內(nèi)部事務(wù),對(duì)于DataSourceTransactionManager來(lái)說(shuō)創(chuàng)建的內(nèi)部事務(wù)就是DataSourceTransactionObjectObject transaction = this.transaction;if (!(transaction instanceof SavepointManager)) {throw new NestedTransactionNotSupportedException("Transaction object [" + this.transaction + "] does not support savepoints");}return (SavepointManager) transaction; }

    createSavepoint用于從當(dāng)前保存點(diǎn)管理器(事務(wù)對(duì)象)中創(chuàng)建一個(gè)保存點(diǎn),實(shí)際上就是獲取事務(wù)對(duì)象里面的ConnectionHolder,然后在獲取ConnectionHolder里面的Connection,最后調(diào)用Connection.setSavepoint方法創(chuàng)建并獲取保存點(diǎn)。

    /*** DataSourceTransactionObject的父類JdbcTransactionObjectSupport的方法* <p>* 創(chuàng)建一個(gè)JDBC 3.0保存點(diǎn)并返回它。*/ @Override public Object createSavepoint() throws TransactionException {//校驗(yàn)規(guī)則并獲取,此前創(chuàng)建的ConnectionHolder,其內(nèi)部保存了獲取的連接ConnectionConnectionHolder conHolder = getConnectionHolderForSavepoint();try {//如果不允許保存點(diǎn),那么拋出異常,默認(rèn)允許if (!conHolder.supportsSavepoints()) {throw new NestedTransactionNotSupportedException("Cannot create a nested transaction because savepoints are not supported by your JDBC driver");}//如果被設(shè)置為僅回滾,那么拋出異常if (conHolder.isRollbackOnly()) {throw new CannotCreateTransactionException("Cannot create savepoint for transaction which is already marked as rollback-only");}return conHolder.createSavepoint();} catch (SQLException ex) {throw new CannotCreateTransactionException("Could not create JDBC savepoint", ex);} }/*** DataSourceTransactionObject的父類JdbcTransactionObjectSupport的方法* <p>* 為了創(chuàng)建一個(gè)JDBC 3.0保存而獲取ConnectionHolder。*/ protected ConnectionHolder getConnectionHolderForSavepoint() throws TransactionException {//如果不允許保存點(diǎn),那么拋出異常,默認(rèn)允許if (!isSavepointAllowed()) {throw new NestedTransactionNotSupportedException("Transaction manager does not allow nested transactions");}//如果沒(méi)有ConnectionHolder,那么拋出異常,默認(rèn)允許if (!hasConnectionHolder()) {throw new TransactionUsageException("Cannot create nested transaction when not exposing a JDBC transaction");}//返回此前創(chuàng)建的ConnectionHolder,其內(nèi)部保存了獲取的連接return getConnectionHolder(); }//ConnectionHolder的方法的屬性/*** 保存點(diǎn)名稱的前綴。*/ public static final String SAVEPOINT_NAME_PREFIX = "SAVEPOINT_";/*** 從此連接中獲取的保存點(diǎn)的數(shù)量*/ private int savepointCounter = 0;/*** ConnectionHolder的方法* 為當(dāng)前連接創(chuàng)建一個(gè)新的JDBC 3.0保存點(diǎn),只用SAVEPOINT_+savepointCounter作為保存點(diǎn)的名稱** @return 新的保存點(diǎn)* @throws SQLException if thrown by the JDBC driver*/ public Savepoint createSavepoint() throws SQLException {//獲取數(shù)量自增1this.savepointCounter++;//獲取內(nèi)部的JDBC連接,并通過(guò)連接設(shè)置一個(gè)保存點(diǎn),返回創(chuàng)建的Savepointreturn getConnection().setSavepoint(SAVEPOINT_NAME_PREFIX + this.savepointCounter); }

    四、小結(jié)

  • createTransactionIfNecessary方法創(chuàng)建并返回一個(gè)TransactionInfo對(duì)象,并且在此過(guò)程中,將會(huì)調(diào)用getTransaction方法獲取事務(wù)TransactionStatus。

  • getTransaction方法就是Spring事務(wù)處理的核心方法之一,該方法根據(jù)配置的各種事務(wù)傳播行為以及是否存在外層事務(wù)做出不同的處理,方法執(zhí)行完畢將可能開(kāi)啟了新事物,也可能沒(méi)有開(kāi)啟,甚至拋出異常。

  • TransactionInfo內(nèi)部保存了事務(wù)管理器transactionManager、事務(wù)屬性transactionAttribute、全路徑方法名joinpointIdentification。還保存了當(dāng)前方法的事務(wù)transactionStatus,以及前一個(gè)方法的事務(wù)信息對(duì)象oldTransactionInfo。

  • TransactionStatus實(shí)際類型為DefaultTransactionStatus,它持有一個(gè)transaction內(nèi)部事務(wù)對(duì)象、被掛起的事務(wù)資源以及一些事務(wù)的屬性,這個(gè)內(nèi)部事務(wù)對(duì)象由事務(wù)管理器的實(shí)現(xiàn)各自創(chuàng)建,不同的事務(wù)管理器將會(huì)創(chuàng)建不同的類型,因此使用Object來(lái)表示,對(duì)于DataSourceTransactionManager來(lái)說(shuō),它創(chuàng)建的事務(wù)對(duì)象就是DataSourceTransactionObject。

  • DataSourceTransactionObject內(nèi)部持有一個(gè)ConnectionHolder對(duì)象以及一些事務(wù)的屬性,ConnectionHolder對(duì)象內(nèi)部持有一個(gè)為了配置數(shù)據(jù)庫(kù)事務(wù)而獲取的JDBC連接Connection,以及是否開(kāi)啟了事務(wù)的標(biāo)志transactionActive,以及其他屬性,比如保存點(diǎn)計(jì)數(shù)。

  • 最終,我們?yōu)槟硞€(gè)方法定義的事務(wù)屬性,除了傳播行為之外(Spring提供的特性并自行處理),都會(huì)反應(yīng)到Connection的對(duì)應(yīng)操作上,比如隔離級(jí)別、超時(shí)時(shí)間,是否只讀等等,關(guān)鍵方法就是doBegin,該方法用于真正的開(kāi)啟數(shù)據(jù)庫(kù)層面的事務(wù)。

  • 我們用了很長(zhǎng)的文章講解了createTransactionIfNecessary方法的邏輯和源碼,這是Spring 事務(wù)開(kāi)啟的核心處理方法(可能并未真正的開(kāi)啟事務(wù)),剩下的方法比如proceedWithInvocation、completeTransactionAfterThrowing、cleanupTransactionInfo、commitTransactionAfterReturning就是在開(kāi)啟事物之后的處理方法,比如回滾、提交、恢復(fù)事務(wù)等等。

  • 參考文章

    總結(jié)

    以上是生活随笔為你收集整理的Spring TX源码分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

    如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。