對大多數Java開發者來講,Spring事務管理是Spring應用中最經常使用的功能,使用也比較簡單。本文主要從三個方面(基本概述、基於源碼的原理分析以及須要注意的細節)來逐步介紹Spring事務管理的相關知識點及原理,做爲Spring事務管理的學習總結。html
ANSI/ISO SQL92標準定義了4個隔離級別:READ UNCOMMITED、READ COMMITED、REPEATABLE READ和SERIALIZABLE,隔離程度由弱到強。不一樣的事務隔離級別可以解決數據併發問題的能力不一樣,它與數據庫併發性是對立的,二者此消彼長。java
事務傳播主要是爲了描述兩個服務接口方法嵌套調用時,被調用者在調用者有無事務時所採起的事務行爲。Spring框架在TransactionDefinition接口中固定了7種事務傳播行爲:PROPAGATION_REQUIRED、 PROPAGATION_SUPPORTS、 PROPAGATION_MANDATORY、 PROPAGATION_REQUIRES_NEW、 PROPAGATION_NOT_SUPPORTED、 PROPAGATION_NEVER、 PROPAGATION_NESTED。前面的6種是從EJB中引入的,而PROPAGATION_NESTED是Spring特有的。具體可參見深刻淺出事務(4):Spring事務的傳播行爲,該文結合具體代碼示例,通俗易懂。spring
TransactionSynchronizationManager——事務管理的基石,主要是爲了解決事務管理在多線程環境下資源(如Connection、Session等)的併發訪問問題:使用ThreadLocal爲不一樣事務線程維護獨立的資源副本,以及事務配置屬性和運行狀態信息,使各個事務線程互不影響。數據庫
SPI(Service Provider Interface)是一個框架開放給第三方的可擴展服務接口,供其具體實現,以支持框架的擴展性和插件式組件。Spring事務管理SPI主要包括3個接口:PlatformTransactionManager(進行事務的建立、提交或回滾)、TransactionDefinition(定義事務屬性,如隔離級別)和TransactionStatus(事務運行時狀態,如是否已完成)。這三者經過PlatformTransactionManager的以下接口進行關聯:express
// 根據事務定義建立事務,並由TransactionStatus表示它 TransactionStatus getTransaction(TransactionDefinition definition); // 根據事務運行時狀態提交或回滾事務 void commit(TransactionStatus status); void rollback(TransactionStatus status);
三種方式:編程、XML配置和註解。第一方式對應用代碼侵入性較大,現已較少使用。後面兩種則都屬於聲明式事務管理的方式,二者的共同點是都提供事務管理信息的元數據,只不過方式不一樣。前者對代碼的侵入性最小,也最爲經常使用,後者則屬於較爲折衷的方案,有一點侵入性,但相對也較少了配置,各有優劣,依場景需求而定。聲明式事務管理是Spring的一大亮點,利用AOP技術將事務管理做爲切面動態織入到目標業務方法中,讓事務管理簡單易行。編程
而不論是使用哪一種方式,數據源、事務管理器都是必須的,通常經過XML的Bean配置:api
... <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destory-method="close"> <property name="driverClass"><value>${jdbc.driverClass}</value></property> <property name="jdbcUrl"><value>${jdbc.jdbcUrl}</value></property> <property name="user"><value>${jdbc.username}</value></property> <property name="password"><value>${jdbc.password}</value></property> <property name="maxPoolSize"><value>${jdbc.maxPoolSize}</value></property> <property name="minPoolSize"><value>${jdbc.minPoolSize}</value></property> <property name="initialPoolSize"><value>${initialPoolSize}</value></property> </bean> <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource"> <ref local="dataSource" /> </property> <!-- 指定事務管理器標識,可被@Transactional註解引用 --> <qualifier value="txManagerA" /> </bean> ...
採用與DAO模板類同樣的開閉思想,Spring提供了線程安全的TransactionTemplate模板類來處理不變的事務管理邏輯,將變化的部分抽象爲回調接口TransactionCallback供用戶自定義數據訪問邏輯。使用示例:安全
public class ServiceAImpl { private DaoA daoA; @autowried private TransactionTemplate template; public void addElement(final Element ele) { template.execute(new TransactionCallbackWithoutResult() { protected void doInTransactionWithoutResult(TransactionStatus status){ daoA.addElement(ele); } }); } }
TransactionTemplate的配置信息:多線程
... <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> <property name="transactionManager"> <ref local="txManager" /> </property> <property name="isolationLevelName" value="ISOLATION_DEFAULT" /> <property name="propagationBehaviorName" value="PROPAGATION_REQUIRED" /> </bean> ...
固然,用戶也能夠不使用TransactionTemplate,而是直接基於原始的Spring事務管理SPI進行編程式事務管理,只不過這種方式對代碼侵入性最大,不推薦使用,這裏也就很少作介紹了。併發
Spring早期版本,是經過TransactionProxyFactoryBean代理類實施聲明式事務配置,因爲這種方式的種種弊端,後來引入AOP切面描述語言後,提出一種更簡潔的基於Schema的配置方式:tx/aop命名空間,使聲明式事務配置更簡潔便利。
... <bean id="serviceATarget" class="org.sherlocky.book.spring3x.service.ServiceAImpl" /> <bean id="serviceA" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" p:transactionManager-ref="txManager" p:target-ref="serviceATarget"> <property name="transactionAttributes"> <props> <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> ...
... <tx:advice id="txAdvice" transaction-manager="txManager"> <tx:attributes> <tx:method name="create*" propagation="REQUIRED" timeout="300" rollback-for="java.lang.Exception" /> <tx:method name="delete*" propagation="REQUIRED" timeout="300" rollback-for="java.lang.Exception" /> <tx:method name="update*" propagation="REQUIRED" timeout="300" rollback-for="java.lang.Exception" /> <tx:method name="get*" propagation="REQUIRED" read-only="true" timeout="300" /> <tx:method name="*" propagation="REQUIRED" read-only="true" timeout="300" /> </tx:attributes> </tx:advice> <aop:config> <aop:pointcut id="txPointcut" expression="execution(* org.sherlocky.book.spring3x.service.*ServiceA.*(..))" /> <aop:advisor pointcut-ref="txPointcut" advice-ref="txAdvice" /> </aop:config>
經過**@Transactional對須要事務加強的Bean接口、實現類或方法進行標註,在容器中配置tx:annotation-driven**以啓用基於註解的聲明式事務。註解所提供的事務屬性信息與XML配置中的事務信息基本一致,只不過是另外一種形式的元數據而已。使用示例:
@Transactional("txManagerA") public class ServiceAImpl { private DaoA daoA; public void addElement(final Element ele) { ... } }
源碼分析必定要有目的性,至少有一條清晰的主線,好比要搞清楚框架的某一個功能點背後的代碼組織,來龍去脈,而不是一頭扎進源碼裏,無的放矢。本文就從Spring事務管理的三種使用方式入手,逐個分析Spring在背後都爲咱們作了些什麼。
TransactionTemplate是編程式事務管理的入口,源碼以下:
public class TransactionTemplate extends DefaultTransactionDefinition implements TransactionOperations, InitializingBean { private PlatformTransactionManager transactionManager; ... public <T> T execute(TransactionCallback<T> action) throws TransactionException { if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) { return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);【1】 } else { TransactionStatus status = this.transactionManager.getTransaction(this);【2】 T result; try { result = action.doInTransaction(status); } catch (RuntimeException ex) {【3】 // Transactional code threw application exception -> rollback rollbackOnException(status, ex); throw ex; } catch (Error err) {【4】 // Transactional code threw error -> rollback rollbackOnException(status, err); throw err; } catch (Exception ex) {【5】 // Transactional code threw unexpected exception -> rollback rollbackOnException(status, ex); throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception"); } this.transactionManager.commit(status); return result; } } }
TransactionTemplate提供了惟一的編程入口execute,它接受用於封裝業務邏輯的TransactionCallback接口的實例,返回用戶自定義的事務操做結果T。具體邏輯:先是判斷transactionManager是不是接口CallbackPreferringPlatformTransactionManager的實例,如果則直接委託給該接口的execute方法進行事務管理;不然交給它的核心成員PlatformTransactionManager進行事務的建立、提交或回滾操做。
CallbackPreferringPlatformTransactionManger接口擴展自PlatformTransactionManger,根據如下的官方源碼註釋可知,該接口至關因而把事務的建立、提交和回滾操做都封裝起來了,用戶只須要傳入TransactionCallback接口實例便可,而不是像使用PlatformTransactionManger接口那樣,還須要用戶本身顯示調用getTransaction、rollback或commit進行事務管理。
// Implementors of this interface automatically express a preference for // callbacks over programmatic getTransaction, commit and rollback calls. interface CallbackPreferringPlatformTransactionManager extends PlatformTransactionManager{...}
能夠看到transactionTemplate直接擴展自DefaultTransactionDefinition,讓自身具備默認事務定義功能,【1】和【2】處將this做爲execute或getTransaction的實參傳入,說明該事務管理是採用默認的事務配置,能夠看下DefaultTransactionDefinition中定義的默認配置:
... private int propagationBehavior = PROPAGATION_REQUIRED; //經常使用選擇:當前沒有事務,則新建;不然加入到該事務中 private int isolationLevel = ISOLATION_DEFAULT; //使用數據庫默認的隔離級別 private int timeout = TIMEOUT_DEFAULT; //-1,使用數據庫的超時設置 private boolean readOnly = false; //非只讀事務
而TransactionOperations和InitializingBean接口分別定義了以下單個方法。InitializingBean是Spring在初始化所管理的Bean時經常使用的接口,以確保某些屬性被正確的設置或作一些初始化時的後處理操做,可參考InitializingBean的做用。
<T> T execute(TransactionCallback<T> action); //TransactionTemplate的編程接口 void afterPropertiesSet(); //Bean初始化時調用:在成員變量裝配以後
TransactionTemplate實現InitializingBean接口,主要是確保其核心成員transactionManager是否已初始化:
public void afterPropertiesSet() { if (this.transactionManager == null) { throw new IllegalArgumentException("Property 'transactionManager' is required"); } }
從【3】【4】【5】可看出,基於TransactionTemplate的事務管理,在發生RuntimeException、Error或Exception時都會回滾,正常時才提交事務。
該接口在Spring事務管理中扮演着重要角色。看下getTransaction的源碼註釋:
// Return a currently active transaction or create a new one, according to // the specified propagation behavior.
該方法的主要做用就是根據TransactionDefinition返回當前有效事務或新建事務,其中就包含了事務傳播行爲的控制邏輯。其惟一實現就是該接口對應的抽象類AbstractPlatformTransactionManager,這是典型的接口->抽象類->具體實現類三層結構,以提升代碼複用性。其中抽象類是負責實現一些共有邏輯,而具體子類則是各自實現差別化功能:
// 聲明爲final,確保不能再被子類重寫 public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { Object transaction = doGetTransaction(); ... if (isExistingTransaction(transaction)) {【1】 return handleExistingTransaction(definition, transaction, debugEnabled); } ... if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY){ throw new IllegalTransactionStateException( "No existing transaction found for transaction marked with propagation 'mandatory'"); } else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { SuspendedResourcesHolder suspendedResources = suspend(null);【2】 ... try { ... } catch (RuntimeException ex) { resume(null, suspendedResources);【3】 throw ex; } catch (Error err) { resume(null, suspendedResources); throw err; } } else { boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null); } }
能夠看到它會根據【1】處的isExistingTransaction方法判斷當前是否有事務而分別做出不一樣的處理,包括掛起和恢復當前事務等,有興趣的童鞋能夠深刻【2】處的supend和【3】處的resume方法,會發現對事務的掛起和恢復操做實際是委託於TransactionSynchronizationManager來作的,而該類在前面也提過到,是Spring管理事務資源的,這幾個重要接口和類的關係漸漸清晰了,因爲篇幅有限,後面打算單獨另起一篇細講。
基於XML和註解的方式都是屬於聲明式事務管理,只是提供元數據的形式不用,索性就一塊兒講了。聲明式事務的核心實現就是利用AOP技術,將事務邏輯做爲環繞加強MethodInterceptor動態織入目標業務方法中。其中的核心類爲TransactionInterceptor。從如下代碼註釋可知,TransactionInterceptor是專用於聲明式事務管理的。
// AOP Alliance MethodInterceptor for declarative transaction // management using the common Spring transaction infrastructure {PlatformTransactionManager} public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {...}
// AOP Alliance MethodInterceptor for declarative transaction // management using the common Spring transaction infrastructure public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {...}
從上述註釋中可知該類是專用於聲明式事務管理的,它的核心方法以下invoke:
public Object invoke(final MethodInvocation invocation) throws Throwable { Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); // If the transaction attribute is null, the method is non-transactional. final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);【1】 final PlatformTransactionManager tm = determineTransactionManager(txAttr);【2】 final String joinpointIdentification = methodIdentification(invocation.getMethod(), targetClass); if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { // Standard transaction demarcation with getTransaction and commit/rollback calls. TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);【3】 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.proceed(); } catch (Throwable ex) { // target invocation exception completeTransactionAfterThrowing(txInfo, ex);【4】 throw ex; } finally { cleanupTransactionInfo(txInfo); } commitTransactionAfterReturning(txInfo);【5】 return retVal; } else { try { Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, new TransactionCallback<Object>() { public Object doInTransaction(TransactionStatus status) { TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); try { return invocation.proceed(); } ... } }); ... } ... } }
TransactionInterceptor實現了MethodInterceptor接口,將事務管理的邏輯封裝在環繞加強的實現中,而目標業務代碼則抽象爲MethodInvocation(該接口擴展自Joinpoint,故實際是AOP中的鏈接點),使得事務管理代碼與業務邏輯代碼徹底分離,能夠對任意目標類進行無侵入性的事務織入。具體邏輯:先根據MethodInvocation獲取事務屬性TransactionAttribute,根據TransactionAttribute獲得對應的PlatformTransactionManager,再根據其是不是CallbackPreferringPlatformTransactionManager的實例分別作不一樣的處理,總體上跟TransactionTemplate中截然不同,後面主要是介紹幾點不一樣的地方。
MethodInterceptor是AOP中的環繞加強接口,同一個鏈接點能夠有多個加強,而TransactionInterceptor擴展自該接口,說明事務管理只是衆多橫切邏輯中的一種,還有不少其餘的,好比像日誌記錄、性能監控等,對於AOP而言並沒有區別,它會按照加強的順序統一處理。關於AOP,後期會單獨一篇詳細介紹。
在代碼【1】處,委託給TransactionAttributeSource根據MethodInvocation獲取對應的事務屬性TransactionAttribute,先來看下TransactionAttribute:
public interface TransactionAttribute extends TransactionDefinition { /** * Return a qualifier value associated with this transaction attribute. * <p>This may be used for choosing a corresponding transaction manager * to process this specific transaction. */ String getQualifier(); /** * Should we roll back on the given exception? * @param ex the exception to evaluate * @return whether to perform a rollback or not */ boolean rollbackOn(Throwable ex); }
就是在TransactionDefinition的基礎上增長了兩個可定製屬性,使用過XML配置和註解方式的童鞋應該都對qualifier和rollback-for再熟悉不過了,那兩個新增屬性就是爲了支持這兩個配置項的。再來看下TransactionAttributeSource:
/** * Interface used by TransactionInterceptor. Implementations know * how to source transaction attributes, whether from configuration, * metadata attributes at source level, or anywhere else. * @see TransactionInterceptor#setTransactionAttributeSource * @see TransactionProxyFactoryBean#setTransactionAttributeSource */ public interface TransactionAttributeSource { TransactionAttribute getTransactionAttribute(Method method, Class<?> targetClass); }
之因此有這個接口,是由於Spring提供了XML配置、註解等不一樣的事務元數據形式,即事務屬性的來源多樣,該接口正是將事務配置的來源進行抽象,不一樣的來源有對應不一樣的實現類,接口單一職責,巧妙精簡的設計!類圖以下,AnnotationTransactionAttributeSource是註解相關,而NameMatchTransactionAttributeSource、MatchAlwaysTransactionAttributeSource等是XML配置相關。
該抽象父類是事務切面的基本處理類,實現了一些共有方法,如代碼【2】處determineTransactionManager(..)根據TransactionAttribute獲得對應的PlatformTransactionManager,以及【3】處createTransactionIfNecessary建立事務,【4】處completeTransactionAfterThrowing回滾事務,【5】處commitTransactionAfterReturning提交事務等基本操做,底層一樣是委託PlatformTransactionManager進行處理的。這裏主要看下事務的回滾操做,跟TransactionTemplate是有區別的:
protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) { if (txInfo != null && txInfo.hasTransaction()) { ... if (txInfo.transactionAttribute.rollbackOn(ex)) {【1】 try { txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); } catch (TransactionSystemException ex2) { logger.error("Application exception overridden by rollback exception", ex); ex2.initApplicationException(ex); throw ex2; } catch (RuntimeException ex2) { logger.error("Application exception overridden by rollback exception", ex); throw ex2; } catch (Error err) { logger.error("Application exception overridden by rollback error", ex); throw err; } } else { try { txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); } ... } } }
從【1】處的transactionAttribute.rollbackon(ex)可看出,事務屬性中的rollbackOn是在這裏生效的,在發生指定異常時選擇回滾或提交,是用戶可配置的,而不像TransactionTemplate是固定的所有回滾。
該類是早期基於Bean的XML配置方式實現聲明式事務的核心類,之因此放在後面講,是由於該方式已不被推薦使用,先來看下定義:
/** * Proxy factory bean for simplified declarative transaction handling. * This is a convenient alternative to a standard AOP * {@link org.springframework.aop.framework.ProxyFactoryBean} * with a separate {@link TransactionInterceptor} definition. * * <p><strong>HISTORICAL NOTE:</strong> This class was originally designed to cover the * typical case of declarative transaction demarcation: namely, wrapping a singleton * target object with a transactional proxy, proxying all the interfaces that the target * implements. However, in Spring versions 2.0 and beyond, the functionality provided here * is superseded by the more convenient {@code tx:} XML namespace. See the <a * href="http://bit.ly/qUwvwz">declarative transaction management</a> section of the * Spring reference documentation to understand the modern options for managing * transactions in Spring applications. * ... */ public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean implements BeanFactoryAware { private final TransactionInterceptor transactionInterceptor = new TransactionInterceptor(); private Pointcut pointcut; ... protected Object createMainInterceptor() { this.transactionInterceptor.afterPropertiesSet(); if (this.pointcut != null) { return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor); } else { // Rely on default pointcut. return new TransactionAttributeSourceAdvisor(this.transactionInterceptor); } } }
源碼的聲明已經至關清晰,大體說明了該類的前因後果,忍不住直接貼上來了,感興趣可自行閱讀。這裏主要是看下其實現思路:事務處理邏輯是委託給其成員TransactionInterceptor,而將事務邏輯織入目標類的工做則交由AbstractSingletonProxyFactoryBean來處理。FactoryBean是Spring中普遍使用的用來定製一些較複雜Bean的實例化邏輯,所以從類名上就可看出,AbstractSingletonProxyFactoryBean的主要工做則是實例化並返回一個單例的Proxy對象。有了Proxy對象,織入的工做就垂手可得了,此時TransactionInterceptor只是Proxy的衆多Advisor中的一個,最後由Proxy建立擁有了事務加強的代理對象便可。
如下是AbstractSingletonProxyFactoryBean中Proxy的實例化過程,所有在afterPropertiesSet中完成。其中的createMainInterceptor()是在其子類TransactionProxyFactoryBean中實現的,對應事務加強邏輯。
public abstract class AbstractSingletonProxyFactoryBean extends ProxyConfig implements FactoryBean<Object>, BeanClassLoaderAware, InitializingBean { ... public void afterPropertiesSet() { if (this.target == null) { throw new IllegalArgumentException("Property 'target' is required"); } if (this.target instanceof String) { throw new IllegalArgumentException("'target' needs to be a bean reference, not a bean name as value"); } if (this.proxyClassLoader == null) { this.proxyClassLoader = ClassUtils.getDefaultClassLoader(); } ProxyFactory proxyFactory = new ProxyFactory();【1】 if (this.preInterceptors != null) { for (Object interceptor : this.preInterceptors) { proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor)); } } // Add the main interceptor (typically an Advisor). proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(createMainInterceptor())); if (this.postInterceptors != null) { for (Object interceptor : this.postInterceptors) { proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor)); } } proxyFactory.copyFrom(this); TargetSource targetSource = createTargetSource(this.target); proxyFactory.setTargetSource(targetSource); if (this.proxyInterfaces != null) { proxyFactory.setInterfaces(this.proxyInterfaces); } else if (!isProxyTargetClass()) { // Rely on AOP infrastructure to tell us what interfaces to proxy. proxyFactory.setInterfaces( ClassUtils.getAllInterfacesForClass(targetSource.getTargetClass(), this.proxyClassLoader)); } this.proxy = proxyFactory.getProxy(this.proxyClassLoader); } }
從代碼【1】處能夠看到,ProxyFactory是建立Proxy對象的關鍵類,感興趣的童鞋能夠跟進ProxyFactory的代碼,可發現最終建立Proxy對象的是DefaultAopProxyFactory,細節以下:根據config配置,選擇建立咱們所熟知的兩種AopProxy:JDK的JdkDynamicAopProxy和Cglib的Cglib2AopProxy。
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable { ... public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException { if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) { Class targetClass = config.getTargetClass(); if (targetClass == null) { throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation."); } if (targetClass.isInterface()) { return new JdkDynamicAopProxy(config); } if (!cglibAvailable) { throw new AopConfigException( "Cannot proxy target class because CGLIB2 is not available. " + "Add CGLIB to the class path or specify proxy interfaces."); } return CglibProxyFactory.createCglibProxy(config); } else { return new JdkDynamicAopProxy(config); } } }
當使用PROPAGATION_NESTED時,底層的數據源必須基於JDBC3.0。由於Spring所支持的嵌套事務,是基於事務保存點實現的(JTA除外),而保存點機制是從JDBC3.0纔開始出現的。直接看AbstractPlatformTransactionManager中的處理代碼。對於一般的嵌套事務,會在當前所處父事務中建立保存點,而後進行子事務處理;對於JTA事務環境,則是採用嵌套的begin和commit/rollback調用來處理。
private TransactionStatus handleExistingTransaction( TransactionDefinition definition, Object transaction, boolean debugEnabled) throws TransactionException { ... if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { 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() + "]"); } if (useSavepointForNestedTransaction()) { // Create savepoint within existing Spring-managed transaction, // through the SavepointManager API implemented by TransactionStatus. // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization. DefaultTransactionStatus status = prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null); status.createAndHoldSavepoint(); return status; } else { // Nested transaction through nested begin and commit/rollback calls. // Usually only for JTA: Spring synchronization might get activated here // in case of a pre-existing JTA transaction. boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); DefaultTransactionStatus status = newTransactionStatus( definition, transaction, true, newSynchronization, debugEnabled, null); doBegin(transaction, definition); prepareSynchronization(status, definition); return status; } } ... }
當脫離模板類,直接操做底層持久技術的原生API時,就須要經過Spring提供的資源工具類獲取線程綁定的資源,而不該該直接從DataSource或SessionFactory中獲取,不然容易形成數據鏈接泄露的問題。Spring爲不一樣的持久化技術提供了一套從TransactionSynchronizationManager中獲取對應線程綁定資源的工具類:DataSourceUtils(Spring JDBC或iBatis)、SessionFactoryUtils(Hibernate 3.0)等。
雖然@Transactional註解可被應用於接口、接口方法、類及類的public方法,但建議在具體實現類上使用@Transactional註解,由於接口上的註解不能被繼承,這樣會有隱患(關於註解的繼承,可參考這裏)。當事務配置按以下方式,使用的是子類代理(CGLib)而非接口代理(JDK)時,對應目標類不會添加事務加強!
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true" />