国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Spring聲明式事務(wù)管理源碼解讀之事務(wù)提交(轉(zhuǎn)載)
/**
*作者:張榮華(ahuaxuan)
*2007-06-16
*轉(zhuǎn)載請(qǐng)注明出處及作者
*/

Spring聲明式事務(wù)管理源碼解讀

簡介:事務(wù)是所有企業(yè)應(yīng)用系統(tǒng)的核心,之前人們使用ejb的時(shí)候,容器事務(wù)管理(CMT),是slsb最令人稱道的地方,據(jù)說很多人使用ejb,使用slsb就是為了cmt,但是spring出現(xiàn)之后,格局就變了,因?yàn)槌绦騿T又多了一種選擇,就是聲明式事務(wù)管理,聲明式事務(wù)管理是基于AOP的,及AOP是它的底層特性,本文的目的就是為了和大家探討一下spring的聲明式事務(wù)管理,從源代碼來分析它的背后的思想。(謝謝異常的建議,因?yàn)楸疚脑瓉頉]有簡介


這個(gè)是我昨天在解決問題是看源碼得一點(diǎn)體驗(yàn),可能說得比較大概,希望大家多多討論,把本貼得質(zhì)量提高上去,因?yàn)閟pring實(shí)現(xiàn)的事務(wù)管理這部分我相信還是有點(diǎn)復(fù)雜的。一個(gè)人未必能想得十分清楚
在spring的聲明式事務(wù)管理中,它是如何判定一個(gè)及標(biāo)記一個(gè)方法是否應(yīng)該是處在事務(wù)體之中呢。

首先要理解的是spring是如何來標(biāo)記一個(gè)方法是否應(yīng)該處在事務(wù)體之中的。有這樣一個(gè)接口TransactionDefinition,其中定義了很多常量,它還有一個(gè)子接口TransactionAttribute,其中只有一個(gè)方法rollback。
TransactionDefinition中有很多常量定義,它們分別屬于兩種類型,傳播途徑和隔離級(jí)別
Java代碼
  1. /** 
  2.      * Support a current transaction, create a new one if none exists. 
  3.      * Analogous to EJB transaction attribute of the same name. 
  4.      * <p>This is typically the default setting of a transaction definition. 
  5.      */  
  6.     int PROPAGATION_REQUIRED = 0;  
當(dāng)然其中也定義了隔離級(jí)別
/**
Java代碼
  1. * A constant indicating that dirty reads are prevented; non-repeatable reads  
  2.  * and phantom reads can occur. This level only prohibits a transaction  
  3.  * from reading a row with uncommitted changes in it.  
  4.  * @see java.sql.Connection#TRANSACTION_READ_COMMITTED  
  5.  */  
  6. int ISOLATION_READ_COMMITTED   = Connection.TRANSACTION_READ_COMMITTED;  
同時(shí)還有兩個(gè)對(duì)應(yīng)的方法來得到這樣的傳播途徑和隔離級(jí)別
Java代碼
  1. /** 
  2.      * Return the propagation behavior. 
  3.      * Must return one of the PROPAGATION constants. 
  4.      * @see #PROPAGATION_REQUIRED 
  5.      * @see org.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive() 
  6.      */  
  7.     int getPropagationBehavior();  
  8.   
  9.     /** 
  10.      * Return the isolation level. 
  11.      * Must return one of the ISOLATION constants. 
  12.      * <p>Only makes sense in combination with PROPAGATION_REQUIRED or 
  13.      * PROPAGATION_REQUIRES_NEW. 
  14.      * <p>Note that a transaction manager that does not support custom 
  15.      * isolation levels will throw an exception when given any other level 
  16.      * than ISOLATION_DEFAULT. 
  17.      * @see #ISOLATION_DEFAULT 
  18.      */  
  19.     int getIsolationLevel();  
這個(gè)接口有一個(gè)默認(rèn)的實(shí)現(xiàn)DefaultTransactionDefinition。然后它還有子類,比如說
DefaultTransactionAttribute。Spring在判斷一個(gè)方法是否需要事務(wù)體的時(shí)候其實(shí)是創(chuàng)建一個(gè)TransactionAttribute實(shí)現(xiàn)的實(shí)例.

有了上面的簡單介紹就可以進(jìn)入真正判斷是否需要事務(wù)的地方了。這個(gè)方法在TransactionAspectSupport類里,


Java代碼
  1. /** 
  2.      * Create a transaction if necessary. 
  3.      * @param method method about to execute 
  4.      * @param targetClass class the method is on 
  5.      * @return a TransactionInfo object, whether or not a transaction was created. 
  6.      * The hasTransaction() method on TransactionInfo can be used to tell if there 
  7.      * was a transaction created. 
  8.      */  
  9.     protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) {  
  10.         // If the transaction attribute is null, the method is non-transactional.  
  11.         final TransactionAttribute sourceAttr =  
  12.                 this.transactionAttributeSource.getTransactionAttribute(method, targetClass);//就是在這里判斷了這個(gè)方法的事務(wù)屬性  
  13.         TransactionAttribute txAttr = sourceAttr;  
  14.   
  15.         // If no name specified, apply method identification as transaction name.  
  16.         if (txAttr != null && txAttr.getName() == null) {  
  17.             final String name = methodIdentification(method);  
  18.             txAttr = new DelegatingTransactionAttribute(sourceAttr) {  
  19.                 public String getName() {  
  20.                     return name;  
  21.                 }  
  22.             };  
  23.         }  
  24.   
  25.         TransactionInfo txInfo = new TransactionInfo(txAttr, method);  
  26. //TransactionInfo是TransactionAspectSupport的一個(gè)內(nèi)部類,它的主要功能是記錄方法和對(duì)應(yīng)的事務(wù)屬性  
  27.         if (txAttr != null) {  
  28.             // We need a transaction for this method  
  29.             if (logger.isDebugEnabled()) {  
  30.                 logger.debug("Getting transaction for " + txInfo.joinpointIdentification());  
  31.             }  
  32.   
  33.             // The transaction manager will flag an error if an incompatible tx already exists  
  34.             txInfo.newTransactionStatus(this.transactionManager.getTransaction(txAttr));//這個(gè)方法要仔細(xì)的看  
  35.         }  
  36.         else {  
  37.             // The TransactionInfo.hasTransaction() method will return  
  38.             // false. We created it only to preserve the integrity of  
  39.             // the ThreadLocal stack maintained in this class.  
  40.             if (logger.isDebugEnabled())  
  41.                 logger.debug("Don't need to create transaction for [" + methodIdentification(method) +  
  42.                         "]: this method isn't transactional");  
  43.         }  
  44.   
  45.         // We always bind the TransactionInfo to the thread, even if we didn't create  
  46.         // a new transaction here. This guarantees that the TransactionInfo stack  
  47.         // will be managed correctly even if no transaction was created by this aspect.  
  48.         txInfo.bindToThread();  
  49.         return txInfo;  
  50.     }  

TransactionInfo是TransactionAspectSupport的一個(gè)內(nèi)部類,它的主要功能是記錄方法和對(duì)應(yīng)的事務(wù)屬性,在上面這個(gè)方法的最后,這個(gè)TransactionInfo對(duì)象被保存到當(dāng)前線程中。

而這個(gè)方法會(huì)在事務(wù)攔截器TransactionInterceptor中被調(diào)用,TransactionInterceptor實(shí)際上是TransactionAspectSupport的子類,看看其中的invoke方法:
Java代碼
  1. // Work out the target class: may be <code>null</code>.  
  2.         // The TransactionAttributeSource should be passed the target class  
  3.         // as well as the method, which may be from an interface  
  4.         Class targetClass = (invocation.getThis() != null) ? invocation.getThis().getClass() : null;  
  5.           
  6.         // Create transaction if necessary.  
  7.         TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);  
  8.   
  9.         Object retVal = null;  
  10.         try {  
  11.             // This is an around advice.  
  12.             // Invoke the next interceptor in the chain.  
  13.             // This will normally result in a target object being invoked.  
  14.             retVal = invocation.proceed();  
  15.         }  
  16.         catch (Throwable ex) {  
  17.             // target invocation exception  
  18.             doCloseTransactionAfterThrowing(txInfo, ex);  
  19.             throw ex;  
  20.         }  
  21.         finally {  
  22.             doFinally(txInfo);  
  23.         }  
  24.         doCommitTransactionAfterReturning(txInfo);//在這里執(zhí)行方法結(jié)束之后需要的操作  
  25.         return retVal;  

這個(gè)方法就如同一般的interceptor需要實(shí)現(xiàn)的方法一樣。只不過在這個(gè)方法里判斷被反射的方法是否需要事務(wù)。

接著我們重點(diǎn)再回頭看一下createTransactionIfNecessary方法里的這一句:
txInfo.newTransactionStatus(this.transactionManager.getTransaction(txAttr));
接著我們就應(yīng)該去看看這個(gè)getTransaction方法了,假設(shè)我們是使用hibernate3,其他類似。看getTransaction之前我們來看一下這兩類和一個(gè)接口
接口PlatformTransactionManager
抽象類public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager
類public class HibernateTransactionManager extends AbstractPlatformTransactionManager,很明顯,這里有一個(gè)方法模板模式。
那我們看一下AbstractPlatformTransactionManager中得getTransaction方法:
Java代碼
  1. public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {  
  2.         Object transaction = doGetTransaction();//抽象方法,也需要子類實(shí)現(xiàn),這個(gè)方法同樣很重要  
  3.   
  4.         // Cache debug flag to avoid repeated checks.  
  5.         boolean debugEnabled = logger.isDebugEnabled();  
  6.         if (debugEnabled) {  
  7.             logger.debug("Using transaction object [" + transaction + "]");  
  8.         }  
  9.   
  10.         if (definition == null) {  
  11.             // Use defaults if no transaction definition given.  
  12.             definition = new DefaultTransactionDefinition();  
  13.         }  
  14.   
  15.         if (isExistingTransaction(transaction)) {  
  16.             // Existing transaction found -> check propagation behavior to find out how to behave.  
  17.             return handleExistingTransaction(definition, transaction, debugEnabled);  
  18.         }  
  19.   
  20.         // Check definition settings for new transaction.  
  21.         if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {  
  22.             throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());  
  23.         }  
  24.   
  25.         // No existing transaction found -> check propagation behavior to find out how to behave.  
  26.         if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {  
  27.             throw new IllegalTransactionStateException(  
  28.                     "Transaction propagation 'mandatory' but no existing transaction found");  
  29.         }  
  30.         else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||  
  31.                 definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||  
  32.             definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {  
  33.             if (debugEnabled) {  
  34.                 logger.debug("Creating new transaction with name [" + definition.getName() + "]");  
  35.             }  
  36.             doBegin(transaction, definition);  
  37.             boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);  
  38.             return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);  
  39.         }  
  40.         else {  
  41.             // Create "empty" transaction: no actual transaction, but potentially synchronization.  
  42.             boolean newSynchronization = (this.transactionSynchronization == SYNCHRONIZATION_ALWAYS);  
  43.             return newTransactionStatus(definition, nullfalse, newSynchronization, debugEnabled, null);  
  44.         }  
  45.     }  
上面的代碼很多地方都有解釋,所以很好理解,這段代碼的關(guān)鍵部分在doBegin(transaction,definition)這里(這是一個(gè)抽象方法,子類必須實(shí)現(xiàn)這個(gè)方法,
具體依賴于抽象,這個(gè)是對(duì)方法模板模式的一個(gè)概括。),前面講到我們假設(shè)是使用hibernate,那么就看看HibernateTransactionManager這個(gè)類吧,doBegin里的參數(shù)1,transaction其實(shí)是HibernateTransactionObject的一個(gè)實(shí)例,這個(gè)實(shí)例里主要存放的就是sessionholder,sessionholder里存放的就是開始事務(wù)的session和transaction對(duì)象,如果之前沒有sessionholder存放到線程中,那么這個(gè)HibernateTransactionObject的實(shí)例的屬性其實(shí)是空的,這一點(diǎn)可以在doBegin方法的實(shí)現(xiàn)中看出來
Java代碼
  1. protected void doBegin(Object transaction, TransactionDefinition definition) {  
  2.         if (getDataSource() != null && TransactionSynchronizationManager.hasResource(getDataSource())) {  
  3.             throw new IllegalTransactionStateException(  
  4.                     "Pre-bound JDBC Connection found - HibernateTransactionManager does not support " +  
  5.                     "running within DataSourceTransactionManager if told to manage the DataSource itself. " +  
  6.                     "It is recommended to use a single HibernateTransactionManager for all transactions " +  
  7.                     "on a single DataSource, no matter whether Hibernate or JDBC access.");  
  8.         }  
  9.   
  10.         Session session = null;  
  11.   
  12.         try {  
  13.             HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;  
  14.             if (txObject.getSessionHolder() == null) {  
  15.                 Interceptor entityInterceptor = getEntityInterceptor();  
  16.                 Session newSession = (entityInterceptor != null ?  
  17.                         getSessionFactory().openSession(entityInterceptor) : getSessionFactory().openSession());  
  18.                 if (logger.isDebugEnabled()) {  
  19.                     logger.debug("Opened new Session [" + newSession + "] for Hibernate transaction");  
  20.                 }  
  21.                 txObject.setSessionHolder(new SessionHolder(newSession), true);  
}//我們看到,如果傳進(jìn)來的transaction中并沒有存放sessionholder,那么就新建一個(gè)session,放到新的sessionholder中,再放到HibernateTransactionObject的實(shí)例中去,順便說一下,這個(gè)變量的名字取得真是差,雖然是Juergen Hoeller寫的,也要批一下,搞得別人會(huì)以為是Transaction的實(shí)例

Java代碼
  1. txObject.getSessionHolder().setSynchronizedWithTransaction(true);  
  2.             session = txObject.getSessionHolder().getSession();  
  3.   
  4.             Connection con = session.connection();  
  5.             Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);  
  6.             txObject.setPreviousIsolationLevel(previousIsolationLevel);  
  7.   
  8.             if (definition.isReadOnly() && txObject.isNewSessionHolder()) {  
  9.                 // Just set to NEVER in case of a new Session for this transaction.  
  10.                 session.setFlushMode(FlushMode.NEVER);  
  11.             }//如果是只讀事務(wù),并且sessionholder是新建的,那么就設(shè)置hibernate的flushmode為never  
  12.   
  13.             if (!definition.isReadOnly() && !txObject.isNewSessionHolder()) {  
  14.                 // We need AUTO or COMMIT for a non-read-only transaction.  
  15.                 FlushMode flushMode = session.getFlushMode();  
  16.                 if (FlushMode.NEVER.equals(flushMode)) {  
  17.                     session.setFlushMode(FlushMode.AUTO);  
  18. //如果session的flushmode是nerver,就設(shè)置為auto,因?yàn)槿绻聞?wù)定義成非readonly,那么這個(gè)session一定是可以flush的  
  19.                     txObject.getSessionHolder().setPreviousFlushMode(flushMode);  
  20.                 }  
  21.             }  
  22.   
  23.             // Add the Hibernate transaction to the session holder.  
  24.             txObject.getSessionHolder().setTransaction(session.beginTransaction());//開始一個(gè)事務(wù),并把這個(gè)事務(wù)對(duì)象放到sessionholder中,隨后這個(gè)sessionholder會(huì)通過threadlocal放到線程中,以供在commit時(shí)使用  
  25.   
  26.             // Register transaction timeout.  
  27.             if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {  
  28.                 txObject.getSessionHolder().setTimeoutInSeconds(definition.getTimeout());//設(shè)置超時(shí)時(shí)間,如果其超時(shí)時(shí)間為-1,則不進(jìn)行設(shè)置,如果不是-1,那么超時(shí)時(shí)間是這樣設(shè)置的new Date(System.currentTimeMillis() + millis*1000);既程序員在配置文件中指定的其實(shí)是秒數(shù)  
  29.             }  
  30.   
  31.             // Register the Hibernate Session's JDBC Connection for the DataSource, if set.  
  32.             if (getDataSource() != null) {  
  33.                 ConnectionHolder conHolder = new ConnectionHolder(con);  
  34.                 if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {  
  35.                     conHolder.setTimeoutInSeconds(definition.getTimeout());  
  36.                 }  
  37.                 if (logger.isDebugEnabled()) {  
  38.                     logger.debug("Exposing Hibernate transaction as JDBC transaction [" + con + "]");  
  39.                 }  
  40.                 TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);  
  41.                 txObject.setConnectionHolder(conHolder);  
  42.             }  
  43.   
  44.             // Bind the session holder to the thread.  
  45.             if (txObject.isNewSessionHolder()) {  
  46.                 TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());//如果是新的sessionholder則綁定到線程。這樣在進(jìn)入方法棧中的下一個(gè)方法時(shí)就能得到整個(gè)sessionholder了,connectionholder亦是如此  
  47.             }  
  48.         }  
  49. catch (Exception ex) {  
  50.             SessionFactoryUtils.releaseSession(session, getSessionFactory());//如果拋出異常就釋放這個(gè)session,這個(gè)操作還會(huì)在后面出現(xiàn)  
  51.             throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);  
  52.         }  
  53.     }  
通過以上對(duì)代碼的注釋可以知道,如果給service設(shè)置聲明式事務(wù)管理,假設(shè)事務(wù)傳播途徑為required,然后一個(gè)service調(diào)用另一個(gè)service時(shí),他們其實(shí)是共用一個(gè)session,原則是沒有就創(chuàng)建,有就不創(chuàng)建,并返回之前已創(chuàng)建的session和transaction。也就是說spring通過threadlocal把session和對(duì)應(yīng)的transaction放到線程之中,保證了在整個(gè)方法棧的任何一個(gè)地方都能得到同一個(gè)session和transaction。
所以如果你的方法在事務(wù)體之內(nèi),那么你只要通過hibernatesupportdao或者h(yuǎn)ibernatetemplate來得到session的話,那這個(gè)session一定是開始事務(wù)的那個(gè)session,這個(gè)得到session的主要方法在SessionFactoryUtils里,我們來看一下
(這里還有一個(gè)小細(xì)節(jié),public abstract class SessionFactoryUtils ,JuergenHoeller在寫工具類的時(shí)候?yàn)榱瞬荒茏屍溆袑?shí)例使用的是abstract,而我們一般的做法是final類加private的構(gòu)造方法,看上去不怎么雅觀,看看源代碼還是能學(xué)習(xí)到不少寫代碼的技巧的,這里還有一個(gè)插曲,上次feiing還說java為什么不能弄成final和abstract同時(shí)存在呢,這樣就可以確保既不會(huì)有實(shí)例產(chǎn)生,也不能繼承了,呵呵)
在SessionFactoryUtils的doGetSession里寫到,如果當(dāng)前線程有綁定session,則返回這個(gè)session,如果沒有綁定session,則看是否允許創(chuàng)建(既allowCreate這個(gè)參數(shù)是true還是false,這個(gè)參數(shù)將會(huì)在很多地方設(shè)計(jì)到,比如說hibernatetemplate和hibernatedaosupport里都有),如果不允許創(chuàng)建就拋出一個(gè)原始的hibernateException,舉個(gè)例子,如果你沒有給某個(gè)service方法配置聲明式事務(wù)管理,而卻要在這個(gè)service所調(diào)用的dao里得到當(dāng)前得session,這樣就會(huì)拋這個(gè)錯(cuò)了:
Java代碼
  1. if (method.getName().equals("getCurrentSession")) {  
  2.                 // Handle getCurrentSession method: return transactional Session, if any.  
  3.                 try {  
  4.                     return SessionFactoryUtils.doGetSession((SessionFactory) proxy, false);  
  5. //最后一個(gè)參數(shù)是false,說明這個(gè)方法不能返回一個(gè)新的session,沒有就拋異常  
  6.                 }  
  7.                 catch (IllegalStateException ex) {  
  8.                     throw new HibernateException(ex.getMessage());  
  9.                 }  
  10.             }  

到這里事務(wù)開始部分基本就結(jié)束了
按正常流程,那么接下來就是方法結(jié)束commit的問題了。Commit放到下一篇文章里說吧

我會(huì)把大家正確得觀點(diǎn)不斷得加到貼中,使本貼得質(zhì)量不斷提高,共同進(jìn)步吧,使勁的拍吧

俺寫文章得水平是不行的,希望大家也多提提寫文章技巧方面的意見

修改:這篇文章的后續(xù)篇(spring聲明式事務(wù)源碼解讀之事務(wù)提交)已經(jīng)完成:
http://www.javaeye.com/topic/89072

/**
*作者:張榮華(ahuaxuan)
*2007-06-11
*轉(zhuǎn)載請(qǐng)注明出處及作者
*/

簡介:上次說到spring聲明式事務(wù)管理的事務(wù)開始部分,按流程來講,下面應(yīng)該提交事務(wù)了,spring的聲明式事務(wù)管理其實(shí)是比較復(fù)雜的,事實(shí)上這種復(fù)雜性正是由于事務(wù)本身的復(fù)雜性導(dǎo)致的,如果能用兩三句話就把這部分內(nèi)容說清楚是不現(xiàn)實(shí)的,也是不成熟的,而我對(duì)這部分的理解也可能是不全面的,還是那句話,希望大家和我一起把本貼的質(zhì)量提交起來。
在下面的文章中,我講會(huì)多次提到第一篇文章,第一篇文章的地址是:http://www.javaeye.com/topic/87426
如果要理解事務(wù)提交的話,理解事務(wù)開始是一個(gè)前提條件,所以請(qǐng)先看第一篇文章,再來看這篇
如果你仔細(xì)看下去,我想肯定是有很多收獲,因?yàn)槲覀兇_實(shí)能從spring的代碼和思想中學(xué)到很多東西。

正文:

其實(shí)俺的感覺就是事務(wù)提交要比事務(wù)開始復(fù)雜,看事務(wù)是否提交我們還是要回到TransactionInterceptor類的invoke方法
Java代碼
  1. public Object invoke(MethodInvocation invocation) throws Throwable {  
  2.         // Work out the target class: may be <code>null</code>.  
  3.         // The TransactionAttributeSource should be passed the target class  
  4.         // as well as the method, which may be from an interface  
  5.         Class targetClass = (invocation.getThis() != null) ? invocation.getThis().getClass() : null;  
  6.           
  7.         // Create transaction if necessary.  
  8.         TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);  
  9.   
  10.         Object retVal = null;  
  11.         try {  
  12.             // This is an around advice.  
  13.             // Invoke the next interceptor in the chain.  
  14.             // This will normally result in a target object being invoked.  
  15.             retVal = invocation.proceed();  
  16.         }  
  17.         catch (Throwable ex) {  
  18.             // target invocation exception  
  19.             doCloseTransactionAfterThrowing(txInfo, ex);  
  20.             throw ex;  
  21.         }  
  22.         finally {  
  23.             doFinally(txInfo);//業(yè)務(wù)方法出棧后必須先執(zhí)行的一個(gè)方法  
  24.         }  
  25.         doCommitTransactionAfterReturning(txInfo);  
  26.         return retVal;  
  27.     }  

其中的doFinally(txInfo)那一行很重要,也就是說不管如何,這個(gè)doFinally方法都是要被調(diào)用的,為什么它這么重要呢,舉個(gè)例子:
我們還是以propregation_required來舉例子吧,假設(shè)情況是這樣的,AService中有一個(gè)方法調(diào)用了BService中的,這兩個(gè)方法都處在事務(wù)體之中,他們的傳播途徑都是required。那么調(diào)用開始了,AService的方法首先入方法棧,并創(chuàng)建了TransactionInfo的實(shí)例,接著BService的方法入棧,又創(chuàng)建了一個(gè)TransactionInfo的實(shí)例,而重點(diǎn)要說明的是TransactionInfo是一個(gè)自身關(guān)聯(lián)的內(nèi)部類,第二個(gè)方法入棧時(shí),會(huì)給新創(chuàng)建的TransactionInfo的實(shí)例設(shè)置一個(gè)屬性,就是TransactionInfo對(duì)象中的private TransactionInfooldTransactionInfo;屬性,這個(gè)屬性表明BService方法的創(chuàng)建的TransactionInfo對(duì)象是有一個(gè)old的transactionInfo對(duì)象的,這個(gè)oldTransactionInfo對(duì)象就是AService方法入棧時(shí)創(chuàng)建的TransactionInfo對(duì)象,我們還記得在createTransactionIfNecessary方法里有這樣一個(gè)方法吧:
Java代碼
  1. protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) {  
  2.                 // We always bind the TransactionInfo to the thread, even if we didn't create  
  3.         // a new transaction here. This guarantees that the TransactionInfo stack  
  4.         // will be managed correctly even if no transaction was created by this aspect.  
  5.         txInfo.bindToThread();  
  6.         return txInfo;  
  7.     }  
  8.   
  9. 就是這個(gè)bindToThread()方法在作怪:  
  10. private void bindToThread() {  
  11.             // Expose current TransactionStatus, preserving any existing transactionStatus for  
  12.             // restoration after this transaction is complete.  
  13.             oldTransactionInfo = (TransactionInfo) currentTransactionInfo.get();  
  14.             currentTransactionInfo.set(this);  
  15.         }  

如果當(dāng)前線程中已經(jīng)有了一個(gè)TransactionInfo,則拿出來放到新建的transactionInfo對(duì)象的oldTransactionInfo屬性中,然后再把新建的TransactionInfo設(shè)置到當(dāng)前線程中。

這里有一個(gè)概念要搞清楚,就是TransactionInfo對(duì)象并不是表明事務(wù)狀態(tài)的對(duì)象,表明事務(wù)狀態(tài)的對(duì)象是TransactionStatus對(duì)象,這個(gè)對(duì)象同樣是TransactionInfo的一個(gè)屬性(這一點(diǎn),我在前面一篇文章中并沒有講清楚)。

接下來BService中的那個(gè)方法返回,那么該它退棧了,它退棧后要做的就是doFinally方法,即把它的oldTransactionInfo設(shè)置到當(dāng)前線程中(這個(gè)TransactionInfo對(duì)象顯然就是AService方法入棧時(shí)創(chuàng)建的,怎么現(xiàn)在又要設(shè)置到線程中去呢,原因就是BService的方法出棧時(shí)并不提交事務(wù),因?yàn)锽Service的傳播途徑是required,所以要把棧頂?shù)姆椒ㄋ鶆?chuàng)建transactioninfo給設(shè)置到當(dāng)前線程中),即調(diào)用AService的方法時(shí)所創(chuàng)建的TransactionInfo對(duì)象。那么在AServie的方法出棧時(shí)同樣會(huì)設(shè)置TransactionInfo對(duì)象的oldTransactionInfo到當(dāng)前線程,這時(shí)候顯然oldTransactionInfo是空的,但AService中的方法會(huì)提交事務(wù),所以它的oldTransactionInfo也應(yīng)該是空了。

在這個(gè)小插曲之后,么接下來就應(yīng)該是到提交事務(wù)了,之前在AService的方法出棧時(shí),我們拿到了它入棧時(shí)創(chuàng)建的TransactionInfo對(duì)象,這個(gè)對(duì)象中包含了AService的方法事務(wù)狀態(tài)。即TransactionStatus對(duì)象,很顯然,太顯然了,事務(wù)提交中的任何屬性都和事務(wù)開始時(shí)的創(chuàng)建的對(duì)象息息相關(guān),這個(gè)TransactionStatus對(duì)象哪里來的,我們?cè)倩仡^看看createTransactionIfNessary方法吧:
Java代碼
  1. protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) {  
  2.             txInfo.newTransactionStatus(this.transactionManager.getTransaction(txAttr));  
  3.         }  

再看看transactionManager.getTransaction(txAttr)方法吧:
Java代碼
  1. public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {  
  2.           
  3.         else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||  
  4.                 definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||  
  5.             definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {  
  6.             if (debugEnabled) {  
  7.                 logger.debug("Creating new transaction with name [" + definition.getName() + "]");  
  8.             }  
  9.             doBegin(transaction, definition);  
  10.             boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);  
  11.             return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);//注意這里的返回值,返回的就是一個(gè)TransactionStatus對(duì)象,這個(gè)對(duì)象表明了一個(gè)事務(wù)的狀態(tài),比如說是否是一個(gè)新的事務(wù),事務(wù)是否已經(jīng)結(jié)束,等等,這個(gè)對(duì)象是非常重要的,在事務(wù)提交的時(shí)候還是會(huì)用到它的。        }  
  12.             }  
  13.     }  

還有一點(diǎn)需要說明的是,AService的方法在執(zhí)行之前創(chuàng)建的transactionstatus確實(shí)是通過這個(gè)方法創(chuàng)建的,但是,BService的方法在執(zhí)行之前創(chuàng)建transactionstatus的方法就與這個(gè)不一樣了,下面會(huì)有詳解。

回顧了事務(wù)開始時(shí)所調(diào)用的方法之后,是不是覺得現(xiàn)在對(duì)spring如何處理事務(wù)越來越清晰了呢。由于這么幾個(gè)方法的調(diào)用,每個(gè)方法入棧之前它的事務(wù)狀態(tài)就已經(jīng)被設(shè)置好了。這個(gè)事務(wù)狀態(tài)就是為了在方法出棧時(shí)被調(diào)用而準(zhǔn)備的。

讓我們?cè)俅位氐紹Service中的方法出棧的那個(gè)時(shí)間段,看看spring都做了些什么,我們知道,后入棧的肯定是先出棧,BService中的方法后入棧,拿它肯定要先出棧了,它出棧的時(shí)候是要判斷是否要提交事務(wù),釋放資源的,讓我們來看看TransactionInterceptor的invoke的最后那個(gè)方法doCommitTransactionAfterReturning:

Java代碼
  1. protected void doCommitTransactionAfterReturning(TransactionInfo txInfo) {  
  2.         if (txInfo != null && txInfo.hasTransaction()) {  
  3.             if (logger.isDebugEnabled()) {  
  4.                 logger.debug("Invoking commit for transaction on " + txInfo.joinpointIdentification());  
  5.             }  
  6.             this.transactionManager.commit(txInfo.getTransactionStatus());  
  7. //瞧:提交事務(wù)時(shí)用到了表明事務(wù)狀態(tài)的那個(gè)TransactionStatus對(duì)象了。  
  8.         }  
  9.     }  

看這個(gè)方法的名字就知道spring是要在業(yè)務(wù)方法出棧時(shí)提交事務(wù),貌似很簡單,但是事實(shí)是這樣的嗎? 我們接著往下看。
Java代碼
  1. public final void commit(TransactionStatus status) throws TransactionException {  
  2.         DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;  
  3.   
  4.         if (defStatus.isCompleted()) {  
  5.             throw new IllegalTransactionStateException(  
  6.                     "Transaction is already completed - do not call commit or rollback more than once per transaction");  
  7.         }  
  8.         if (defStatus.isLocalRollbackOnly()) {  
  9.             if (defStatus.isDebug()) {  
  10.                 logger.debug("Transactional code has requested rollback");  
  11.             }  
  12.             processRollback(defStatus);  
  13.             return;  
  14.         }  
  15.         if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {  
  16.             if (defStatus.isDebug()) {  
  17.                 logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");  
  18.             }  
  19.             processRollback(defStatus);  
  20.             throw new UnexpectedRollbackException(  
  21.                     "Transaction has been rolled back because it has been marked as rollback-only");  
  22.         }  
  23.   
  24.         processCommit(defStatus);  
  25.     }  

上面這段代碼就是transactionmanager中的commit,但是看上去,它又把自己的職責(zé)分配給別人了,從代碼里我們看到,如果事務(wù)已經(jīng)結(jié)束了就拋異常,如果事務(wù)是rollbackonly的,那么就rollback吧,但是按照正常流程,我們還是想來看一下,事務(wù)的提交,就是processCommit(status)這個(gè)方法吧。
Java代碼
  1. private void processCommit(DefaultTransactionStatus status) throws TransactionException {  
  2.         try {  
  3.             boolean beforeCompletionInvoked = false;  
  4.             try {  
  5.                 triggerBeforeCommit(status);  
  6.                 triggerBeforeCompletion(status);  
  7.                 beforeCompletionInvoked = true;  
  8.                 if (status.hasSavepoint()) {  
  9.                     if (status.isDebug()) {  
  10.                         logger.debug("Releasing transaction savepoint");  
  11.                     }  
  12.                     status.releaseHeldSavepoint();  
  13.                 }  
  14.                 else if (status.isNewTransaction()) {//這個(gè)判斷非常重要,下面會(huì)詳細(xì)講解這個(gè)判斷的作用  
  15.                     if (status.isDebug()) {  
  16.                         logger.debug("Initiating transaction commit");  
  17.                     }  
  18.                     boolean globalRollbackOnly = status.isGlobalRollbackOnly();  
  19.                     doCommit(status);  
  20.                     // Throw UnexpectedRollbackException if we have a global rollback-only  
  21.                     // marker but still didn't get a corresponding exception from commit.  
  22.                     `````````````````````  
  23.     }  

我們注意到,在判斷一個(gè)事務(wù)是否是新事務(wù)之前還有一個(gè)status.hasSavepoint()的判斷,我認(rèn)為這個(gè)判斷事實(shí)上就是嵌套事務(wù)的判斷,即判斷這個(gè)事務(wù)是否是嵌套事務(wù),如果不是嵌套事務(wù),則再判斷它是否是一個(gè)新事務(wù),下面這段話就非常重要了,BService的中的方法是先出棧的,也就是說在調(diào)用BService之前的創(chuàng)建的那個(gè)事務(wù)狀態(tài)對(duì)象在這里要先被判斷,但是由于在調(diào)用BService的方法之前已經(jīng)創(chuàng)建了一個(gè)Transaction和Session(假設(shè)我們使用的是hibernate3),這時(shí)候在創(chuàng)建第二個(gè)TransactionInfo(再強(qiáng)調(diào)一下吧,TransactionInfo并不是Transaction,Transaction是真正的事務(wù)對(duì)象,TransactionInfo只不過是一個(gè)輔助類而已,用來記錄一系列狀態(tài)的輔助類)的TransactionStatus的時(shí)候就會(huì)進(jìn)入下面這個(gè)方法(當(dāng)然在這之前會(huì)判斷一下當(dāng)前線程中是否已經(jīng)有了一個(gè)SessionHolder對(duì)象,不清楚SessionHolder作用的同學(xué)情況第一篇文章),這個(gè)方法其實(shí)應(yīng)該放到第一篇文章中講的,但是想到如果不講事務(wù)提交就講這個(gè)方法好像沒有這么貼切,廢話少說,我們來看一下吧:
Java代碼
  1. private TransactionStatus handleExistingTransaction(  
  2.             TransactionDefinition definition, Object transaction, boolean debugEnabled)  
  3.             throws TransactionException {  
  4.   
  5.         if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {  
  6.             throw new IllegalTransactionStateException(  
  7.                     "Transaction propagation 'never' but existing transaction found");  
  8.         }  
  9.   
  10.         if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {  
  11.             if (debugEnabled) {  
  12.                 logger.debug("Suspending current transaction");  
  13.             }  
  14.             Object suspendedResources = suspend(transaction);  
  15.             boolean newSynchronization = (this.transactionSynchronization == SYNCHRONIZATION_ALWAYS);  
  16.             return newTransactionStatus(  
  17.                     definition, nullfalse, newSynchronization, debugEnabled, suspendedResources);  
  18.         }  
  19.   
  20.         if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {  
  21.             if (debugEnabled) {  
  22.                 logger.debug("Suspending current transaction, creating new transaction with name [" +  
  23.                         definition.getName() + "]");  
  24.             }  
  25.             Object suspendedResources = suspend(transaction);  
  26.             doBegin(transaction, definition);  
  27.             boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);  
  28.             return newTransactionStatus(  
  29.                     definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);  
  30.         }  
  31.   
  32.         if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {  
  33.             if (!isNestedTransactionAllowed()) {  
  34.                 throw new NestedTransactionNotSupportedException(  
  35.                         "Transaction manager does not allow nested transactions by default - " +  
  36.                         "specify 'nestedTransactionAllowed' property with value 'true'");  
  37.             }  
  38.             if (debugEnabled) {  
  39.                 logger.debug("Creating nested transaction with name [" + definition.getName() + "]");  
  40.             }  
  41.             if (useSavepointForNestedTransaction()) {  
  42.                 // Create savepoint within existing Spring-managed transaction,  
  43.                 // through the SavepointManager API implemented by TransactionStatus.  
  44.                 // Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.  
  45.                 DefaultTransactionStatus status =  
  46.                         newTransactionStatus(definition, transaction, falsefalse, debugEnabled, null);  
  47.                 status.createAndHoldSavepoint();  
  48.                 return status;  
  49.             }  
  50.             else {  
  51.                 // Nested transaction through nested begin and commit/rollback calls.  
  52.                 // Usually only for JTA: Spring synchronization might get activated here  
  53.                 // in case of a pre-existing JTA transaction.  
  54.                 doBegin(transaction, definition);  
  55.                 boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);  
  56.                 return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);  
  57.             }  
  58.         }  
  59.   
  60.         // Assumably PROPAGATION_SUPPORTS.  
  61.         if (debugEnabled) {  
  62.             logger.debug("Participating in existing transaction");  
  63.         }  
  64.         boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);  
  65.         return newTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);  
  66.     }  

我們看到這個(gè)方法其實(shí)很明了,就是什么樣的傳播途徑就創(chuàng)建什么樣的transactionstatus,這個(gè)方法是在事務(wù)開始時(shí)被調(diào)用的,拿到我們之前舉的例子中來看下,我們就恍然大悟了,原來,如果之前已經(jīng)創(chuàng)建過事務(wù),那個(gè)這個(gè)新建的transactionstauts就不應(yīng)該是屬于一個(gè)newTransaction了,所以第3個(gè)參數(shù)就是false了。

也就是說,在BService的方法出棧要要執(zhí)行processcommit,但是由于BService的那個(gè)TransactionStatus不是一個(gè)newTransaction,所以它根本不會(huì)觸發(fā)這個(gè)動(dòng)作:
Java代碼
  1. else if (status.isNewTransaction()) {//這個(gè)判斷非常重要,下面會(huì)詳細(xì)講解這個(gè)判斷的作用  
  2.                     if (status.isDebug()) {  
  3.                         logger.debug("Initiating transaction commit");  
  4.                     }  
  5. boolean globalRollbackOnly = status.isGlobalRollbackOnly();  
  6.                     doCommit(status);  
  7. }  

也就是說在BService的方法出棧后,事務(wù)是不會(huì)提交的。這完全符合propragation_required的模型。
而在AService的方法出棧后,AService的方法所對(duì)應(yīng)的那個(gè)TransactionStatus對(duì)象的newTransaction屬性是為true的,即它會(huì)觸發(fā)上面這段代碼,進(jìn)行真正的事務(wù)提交。讓我們回想一下AService方法入棧之前創(chuàng)建TransactionStatus對(duì)象的情形吧:
newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);看到第3個(gè)參數(shù)為true沒有。

那么事務(wù)該提交了吧,事務(wù)的提交我想使用過hibernate的人都知道怎么提交了:
txObject.getSessionHolder().getTransaction().commit();
從當(dāng)前線程中拿到SessionHolder,再拿到開始事務(wù)的那個(gè)Transaction對(duì)象,然后再commit事務(wù)。在沒有用spring之前,我們經(jīng)常這么做。呵呵。

好吧,我已經(jīng)說到了spring聲明式事務(wù)管理的70%到80%的內(nèi)容了,這70%到80%的內(nèi)容看上去還是非常容易理解的,如果把這兩篇文章認(rèn)真看過,我相信會(huì)有所收獲的,剩下的內(nèi)容需要靠大家自己去挖掘了,因?yàn)榱硎O碌膬?nèi)容可是需要花費(fèi)很多時(shí)間的,因?yàn)闋砍兜臇|西實(shí)在是太多了,呵呵。最后祝大家閱讀愉快,因?yàn)槲业奈墓P實(shí)在是讓大家的眼睛受罪了。
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Spring聲明式事務(wù)管理源碼解讀之事務(wù)提交
源代碼解讀Spring只讀事務(wù)與讀寫事務(wù)的性能的差別
Spring事務(wù)之事務(wù)回滾、清理及提交
Spring 事務(wù)的那些坑,都在這里了!
Hibernate大數(shù)據(jù)量操作解決方案
關(guān)于MyBatis sqlSession的一點(diǎn)整理
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服