/**
*作者:張榮華(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í)別
-
-
-
-
-
- int PROPAGATION_REQUIRED = 0;
/*** Support a current transaction, create a new one if none exists.* Analogous to EJB transaction attribute of the same name.* <p>This is typically the default setting of a transaction definition.*/int PROPAGATION_REQUIRED = 0;
當(dāng)然其中也定義了隔離級(jí)別
/**
- * A constant indicating that dirty reads are prevented; non-repeatable reads
- * and phantom reads can occur. This level only prohibits a transaction
- * from reading a row with uncommitted changes in it.
- * @see java.sql.Connection#TRANSACTION_READ_COMMITTED
- */
- int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
* A constant indicating that dirty reads are prevented; non-repeatable reads* and phantom reads can occur. This level only prohibits a transaction* from reading a row with uncommitted changes in it.* @see java.sql.Connection#TRANSACTION_READ_COMMITTED*/int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
同時(shí)還有兩個(gè)對(duì)應(yīng)的方法來得到這樣的傳播途徑和隔離級(jí)別
-
-
-
-
-
-
- int getPropagationBehavior();
-
-
-
-
-
-
-
-
-
-
-
- int getIsolationLevel();
/*** Return the propagation behavior.* Must return one of the PROPAGATION constants.* @see #PROPAGATION_REQUIRED* @see org.springframework.transaction.support.TransactionSynchronizationManager#isActualTransactionActive()*/int getPropagationBehavior();/*** Return the isolation level.* Must return one of the ISOLATION constants.* <p>Only makes sense in combination with PROPAGATION_REQUIRED or* PROPAGATION_REQUIRES_NEW.* <p>Note that a transaction manager that does not support custom* isolation levels will throw an exception when given any other level* than ISOLATION_DEFAULT.* @see #ISOLATION_DEFAULT*/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類里,
-
-
-
-
-
-
-
-
- protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) {
-
- final TransactionAttribute sourceAttr =
- this.transactionAttributeSource.getTransactionAttribute(method, targetClass);
- TransactionAttribute txAttr = sourceAttr;
-
-
- if (txAttr != null && txAttr.getName() == null) {
- final String name = methodIdentification(method);
- txAttr = new DelegatingTransactionAttribute(sourceAttr) {
- public String getName() {
- return name;
- }
- };
- }
-
- TransactionInfo txInfo = new TransactionInfo(txAttr, method);
-
- if (txAttr != null) {
-
- if (logger.isDebugEnabled()) {
- logger.debug("Getting transaction for " + txInfo.joinpointIdentification());
- }
-
-
- txInfo.newTransactionStatus(this.transactionManager.getTransaction(txAttr));
- }
- else {
-
-
-
- if (logger.isDebugEnabled())
- logger.debug("Don't need to create transaction for [" + methodIdentification(method) +
- "]: this method isn't transactional");
- }
-
-
-
-
- txInfo.bindToThread();
- return txInfo;
- }
/*** Create a transaction if necessary.* @param method method about to execute* @param targetClass class the method is on* @return a TransactionInfo object, whether or not a transaction was created.* The hasTransaction() method on TransactionInfo can be used to tell if there* was a transaction created.*/protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) {// If the transaction attribute is null, the method is non-transactional.final TransactionAttribute sourceAttr =this.transactionAttributeSource.getTransactionAttribute(method, targetClass);//就是在這里判斷了這個(gè)方法的事務(wù)屬性TransactionAttribute txAttr = sourceAttr;// If no name specified, apply method identification as transaction name.if (txAttr != null && txAttr.getName() == null) {final String name = methodIdentification(method);txAttr = new DelegatingTransactionAttribute(sourceAttr) {public String getName() {return name;}};}TransactionInfo txInfo = new TransactionInfo(txAttr, method);//TransactionInfo是TransactionAspectSupport的一個(gè)內(nèi)部類,它的主要功能是記錄方法和對(duì)應(yīng)的事務(wù)屬性if (txAttr != null) {// We need a transaction for this methodif (logger.isDebugEnabled()) {logger.debug("Getting transaction for " + txInfo.joinpointIdentification());}// The transaction manager will flag an error if an incompatible tx already existstxInfo.newTransactionStatus(this.transactionManager.getTransaction(txAttr));//這個(gè)方法要仔細(xì)的看}else {// The TransactionInfo.hasTransaction() method will return// false. We created it only to preserve the integrity of// the ThreadLocal stack maintained in this class.if (logger.isDebugEnabled())logger.debug("Don't need to create transaction for [" + methodIdentification(method) +"]: this method isn't transactional");}// We always bind the TransactionInfo to the thread, even if we didn't create// a new transaction here. This guarantees that the TransactionInfo stack// will be managed correctly even if no transaction was created by this aspect.txInfo.bindToThread();return txInfo;}
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方法:
-
-
-
- Class targetClass = (invocation.getThis() != null) ? invocation.getThis().getClass() : null;
-
-
- TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);
-
- Object retVal = null;
- try {
-
-
-
- retVal = invocation.proceed();
- }
- catch (Throwable ex) {
-
- doCloseTransactionAfterThrowing(txInfo, ex);
- throw ex;
- }
- finally {
- doFinally(txInfo);
- }
- doCommitTransactionAfterReturning(txInfo);
- return retVal;
// Work out the target class: may be <code>null</code>.// The TransactionAttributeSource should be passed the target class// as well as the method, which may be from an interfaceClass targetClass = (invocation.getThis() != null) ? invocation.getThis().getClass() : null;// Create transaction if necessary.TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);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 exceptiondoCloseTransactionAfterThrowing(txInfo, ex);throw ex;}finally {doFinally(txInfo);}doCommitTransactionAfterReturning(txInfo);//在這里執(zhí)行方法結(jié)束之后需要的操作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方法:
- public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
- Object transaction = doGetTransaction();
-
-
- boolean debugEnabled = logger.isDebugEnabled();
- if (debugEnabled) {
- logger.debug("Using transaction object [" + transaction + "]");
- }
-
- if (definition == null) {
-
- definition = new DefaultTransactionDefinition();
- }
-
- if (isExistingTransaction(transaction)) {
-
- return handleExistingTransaction(definition, transaction, debugEnabled);
- }
-
-
- if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
- throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
- }
-
-
- if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
- throw new IllegalTransactionStateException(
- "Transaction propagation 'mandatory' but no existing transaction found");
- }
- else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
- definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
- definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
- if (debugEnabled) {
- logger.debug("Creating new transaction with name [" + definition.getName() + "]");
- }
- doBegin(transaction, definition);
- boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);
- return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);
- }
- else {
-
- boolean newSynchronization = (this.transactionSynchronization == SYNCHRONIZATION_ALWAYS);
- return newTransactionStatus(definition, null, false, newSynchronization, debugEnabled, null);
- }
- }
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {Object transaction = doGetTransaction();//抽象方法,也需要子類實(shí)現(xiàn),這個(gè)方法同樣很重要// Cache debug flag to avoid repeated checks.boolean debugEnabled = logger.isDebugEnabled();if (debugEnabled) {logger.debug("Using transaction object [" + transaction + "]");}if (definition == null) {// Use defaults if no transaction definition given.definition = new DefaultTransactionDefinition();}if (isExistingTransaction(transaction)) {// Existing transaction found -> check propagation behavior to find out how to behave.return handleExistingTransaction(definition, transaction, debugEnabled);}// Check definition settings for new transaction.if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());}// No existing transaction found -> check propagation behavior to find out how to behave.if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {throw new IllegalTransactionStateException("Transaction propagation 'mandatory' but no existing transaction found");}else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {if (debugEnabled) {logger.debug("Creating new transaction with name [" + definition.getName() + "]");}doBegin(transaction, definition);boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);}else {// Create "empty" transaction: no actual transaction, but potentially synchronization.boolean newSynchronization = (this.transactionSynchronization == SYNCHRONIZATION_ALWAYS);return newTransactionStatus(definition, null, false, newSynchronization, debugEnabled, null);}}
上面的代碼很多地方都有解釋,所以很好理解,這段代碼的關(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)中看出來
- protected void doBegin(Object transaction, TransactionDefinition definition) {
- if (getDataSource() != null && TransactionSynchronizationManager.hasResource(getDataSource())) {
- throw new IllegalTransactionStateException(
- "Pre-bound JDBC Connection found - HibernateTransactionManager does not support " +
- "running within DataSourceTransactionManager if told to manage the DataSource itself. " +
- "It is recommended to use a single HibernateTransactionManager for all transactions " +
- "on a single DataSource, no matter whether Hibernate or JDBC access.");
- }
-
- Session session = null;
-
- try {
- HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;
- if (txObject.getSessionHolder() == null) {
- Interceptor entityInterceptor = getEntityInterceptor();
- Session newSession = (entityInterceptor != null ?
- getSessionFactory().openSession(entityInterceptor) : getSessionFactory().openSession());
- if (logger.isDebugEnabled()) {
- logger.debug("Opened new Session [" + newSession + "] for Hibernate transaction");
- }
- txObject.setSessionHolder(new SessionHolder(newSession), true);
protected void doBegin(Object transaction, TransactionDefinition definition) {if (getDataSource() != null && TransactionSynchronizationManager.hasResource(getDataSource())) {throw new IllegalTransactionStateException("Pre-bound JDBC Connection found - HibernateTransactionManager does not support " +"running within DataSourceTransactionManager if told to manage the DataSource itself. " +"It is recommended to use a single HibernateTransactionManager for all transactions " +"on a single DataSource, no matter whether Hibernate or JDBC access.");}Session session = null;try {HibernateTransactionObject txObject = (HibernateTransactionObject) transaction;if (txObject.getSessionHolder() == null) {Interceptor entityInterceptor = getEntityInterceptor();Session newSession = (entityInterceptor != null ?getSessionFactory().openSession(entityInterceptor) : getSessionFactory().openSession());if (logger.isDebugEnabled()) {logger.debug("Opened new Session [" + newSession + "] for Hibernate transaction");}txObject.setSessionHolder(new SessionHolder(newSession), true);
}//我們看到,如果傳進(jìn)來的transaction中并沒有存放sessionholder,那么就新建一個(gè)session,放到新的sessionholder中,再放到HibernateTransactionObject的實(shí)例中去,順便說一下,這個(gè)變量的名字取得真是差,雖然是Juergen Hoeller寫的,也要批一下,搞得別人會(huì)以為是Transaction的實(shí)例
- txObject.getSessionHolder().setSynchronizedWithTransaction(true);
- session = txObject.getSessionHolder().getSession();
-
- Connection con = session.connection();
- Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
- txObject.setPreviousIsolationLevel(previousIsolationLevel);
-
- if (definition.isReadOnly() && txObject.isNewSessionHolder()) {
-
- session.setFlushMode(FlushMode.NEVER);
- }
-
- if (!definition.isReadOnly() && !txObject.isNewSessionHolder()) {
-
- FlushMode flushMode = session.getFlushMode();
- if (FlushMode.NEVER.equals(flushMode)) {
- session.setFlushMode(FlushMode.AUTO);
-
- txObject.getSessionHolder().setPreviousFlushMode(flushMode);
- }
- }
-
-
- txObject.getSessionHolder().setTransaction(session.beginTransaction());
-
-
- if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {
- txObject.getSessionHolder().setTimeoutInSeconds(definition.getTimeout());
- }
-
-
- if (getDataSource() != null) {
- ConnectionHolder conHolder = new ConnectionHolder(con);
- if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {
- conHolder.setTimeoutInSeconds(definition.getTimeout());
- }
- if (logger.isDebugEnabled()) {
- logger.debug("Exposing Hibernate transaction as JDBC transaction [" + con + "]");
- }
- TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);
- txObject.setConnectionHolder(conHolder);
- }
-
-
- if (txObject.isNewSessionHolder()) {
- TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());
- }
- }
- catch (Exception ex) {
- SessionFactoryUtils.releaseSession(session, getSessionFactory());
- throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);
- }
- }
txObject.getSessionHolder().setSynchronizedWithTransaction(true);session = txObject.getSessionHolder().getSession();Connection con = session.connection();Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);txObject.setPreviousIsolationLevel(previousIsolationLevel);if (definition.isReadOnly() && txObject.isNewSessionHolder()) {// Just set to NEVER in case of a new Session for this transaction.session.setFlushMode(FlushMode.NEVER);}//如果是只讀事務(wù),并且sessionholder是新建的,那么就設(shè)置hibernate的flushmode為neverif (!definition.isReadOnly() && !txObject.isNewSessionHolder()) {// We need AUTO or COMMIT for a non-read-only transaction.FlushMode flushMode = session.getFlushMode();if (FlushMode.NEVER.equals(flushMode)) {session.setFlushMode(FlushMode.AUTO);//如果session的flushmode是nerver,就設(shè)置為auto,因?yàn)槿绻聞?wù)定義成非readonly,那么這個(gè)session一定是可以flush的txObject.getSessionHolder().setPreviousFlushMode(flushMode);}}// Add the Hibernate transaction to the session holder.txObject.getSessionHolder().setTransaction(session.beginTransaction());//開始一個(gè)事務(wù),并把這個(gè)事務(wù)對(duì)象放到sessionholder中,隨后這個(gè)sessionholder會(huì)通過threadlocal放到線程中,以供在commit時(shí)使用// Register transaction timeout.if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {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ù)}// Register the Hibernate Session's JDBC Connection for the DataSource, if set.if (getDataSource() != null) {ConnectionHolder conHolder = new ConnectionHolder(con);if (definition.getTimeout() != TransactionDefinition.TIMEOUT_DEFAULT) {conHolder.setTimeoutInSeconds(definition.getTimeout());}if (logger.isDebugEnabled()) {logger.debug("Exposing Hibernate transaction as JDBC transaction [" + con + "]");}TransactionSynchronizationManager.bindResource(getDataSource(), conHolder);txObject.setConnectionHolder(conHolder);}// Bind the session holder to the thread.if (txObject.isNewSessionHolder()) {TransactionSynchronizationManager.bindResource(getSessionFactory(), txObject.getSessionHolder());//如果是新的sessionholder則綁定到線程。這樣在進(jìn)入方法棧中的下一個(gè)方法時(shí)就能得到整個(gè)sessionholder了,connectionholder亦是如此}}catch (Exception ex) {SessionFactoryUtils.releaseSession(session, getSessionFactory());//如果拋出異常就釋放這個(gè)session,這個(gè)操作還會(huì)在后面出現(xiàn)throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);}}
通過以上對(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ò)了:
- if (method.getName().equals("getCurrentSession")) {
-
- try {
- return SessionFactoryUtils.doGetSession((SessionFactory) proxy, false);
-
- }
- catch (IllegalStateException ex) {
- throw new HibernateException(ex.getMessage());
- }
- }
if (method.getName().equals("getCurrentSession")) {// Handle getCurrentSession method: return transactional Session, if any.try {return SessionFactoryUtils.doGetSession((SessionFactory) proxy, false);//最后一個(gè)參數(shù)是false,說明這個(gè)方法不能返回一個(gè)新的session,沒有就拋異常}catch (IllegalStateException ex) {throw new HibernateException(ex.getMessage());}}
到這里事務(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方法
- public Object invoke(MethodInvocation invocation) throws Throwable {
-
-
-
- Class targetClass = (invocation.getThis() != null) ? invocation.getThis().getClass() : null;
-
-
- TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);
-
- Object retVal = null;
- try {
-
-
-
- retVal = invocation.proceed();
- }
- catch (Throwable ex) {
-
- doCloseTransactionAfterThrowing(txInfo, ex);
- throw ex;
- }
- finally {
- doFinally(txInfo);
- }
- doCommitTransactionAfterReturning(txInfo);
- return retVal;
- }
public Object invoke(MethodInvocation invocation) throws Throwable {// Work out the target class: may be <code>null</code>.// The TransactionAttributeSource should be passed the target class// as well as the method, which may be from an interfaceClass targetClass = (invocation.getThis() != null) ? invocation.getThis().getClass() : null;// Create transaction if necessary.TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);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 exceptiondoCloseTransactionAfterThrowing(txInfo, ex);throw ex;}finally {doFinally(txInfo);//業(yè)務(wù)方法出棧后必須先執(zhí)行的一個(gè)方法}doCommitTransactionAfterReturning(txInfo);return retVal;}
其中的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è)方法吧:
- protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) {
-
-
-
- txInfo.bindToThread();
- return txInfo;
- }
-
- 就是這個(gè)bindToThread()方法在作怪:
- private void bindToThread() {
-
-
- oldTransactionInfo = (TransactionInfo) currentTransactionInfo.get();
- currentTransactionInfo.set(this);
- }
protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) {// We always bind the TransactionInfo to the thread, even if we didn't create// a new transaction here. This guarantees that the TransactionInfo stack// will be managed correctly even if no transaction was created by this aspect.txInfo.bindToThread();return txInfo;}就是這個(gè)bindToThread()方法在作怪:private void bindToThread() {// Expose current TransactionStatus, preserving any existing transactionStatus for// restoration after this transaction is complete.oldTransactionInfo = (TransactionInfo) currentTransactionInfo.get();currentTransactionInfo.set(this);}
如果當(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方法吧:
- protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) {
- txInfo.newTransactionStatus(this.transactionManager.getTransaction(txAttr));
- }
protected TransactionInfo createTransactionIfNecessary(Method method, Class targetClass) {txInfo.newTransactionStatus(this.transactionManager.getTransaction(txAttr));}
再看看transactionManager.getTransaction(txAttr)方法吧:
- public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
-
- else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
- definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
- definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
- if (debugEnabled) {
- logger.debug("Creating new transaction with name [" + definition.getName() + "]");
- }
- doBegin(transaction, definition);
- boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);
- return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);
- }
- }
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {if (debugEnabled) {logger.debug("Creating new transaction with name [" + definition.getName() + "]");}doBegin(transaction, definition);boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);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ì)用到它的。 }}}
還有一點(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:
- protected void doCommitTransactionAfterReturning(TransactionInfo txInfo) {
- if (txInfo != null && txInfo.hasTransaction()) {
- if (logger.isDebugEnabled()) {
- logger.debug("Invoking commit for transaction on " + txInfo.joinpointIdentification());
- }
- this.transactionManager.commit(txInfo.getTransactionStatus());
-
- }
- }
protected void doCommitTransactionAfterReturning(TransactionInfo txInfo) {if (txInfo != null && txInfo.hasTransaction()) {if (logger.isDebugEnabled()) {logger.debug("Invoking commit for transaction on " + txInfo.joinpointIdentification());}this.transactionManager.commit(txInfo.getTransactionStatus());//瞧:提交事務(wù)時(shí)用到了表明事務(wù)狀態(tài)的那個(gè)TransactionStatus對(duì)象了。}}
看這個(gè)方法的名字就知道spring是要在業(yè)務(wù)方法出棧時(shí)提交事務(wù),貌似很簡單,但是事實(shí)是這樣的嗎? 我們接著往下看。
- public final void commit(TransactionStatus status) throws TransactionException {
- DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
-
- if (defStatus.isCompleted()) {
- throw new IllegalTransactionStateException(
- "Transaction is already completed - do not call commit or rollback more than once per transaction");
- }
- if (defStatus.isLocalRollbackOnly()) {
- if (defStatus.isDebug()) {
- logger.debug("Transactional code has requested rollback");
- }
- processRollback(defStatus);
- return;
- }
- if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
- if (defStatus.isDebug()) {
- logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
- }
- processRollback(defStatus);
- throw new UnexpectedRollbackException(
- "Transaction has been rolled back because it has been marked as rollback-only");
- }
-
- processCommit(defStatus);
- }
public final void commit(TransactionStatus status) throws TransactionException {DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;if (defStatus.isCompleted()) {throw new IllegalTransactionStateException("Transaction is already completed - do not call commit or rollback more than once per transaction");}if (defStatus.isLocalRollbackOnly()) {if (defStatus.isDebug()) {logger.debug("Transactional code has requested rollback");}processRollback(defStatus);return;}if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {if (defStatus.isDebug()) {logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");}processRollback(defStatus);throw new UnexpectedRollbackException("Transaction has been rolled back because it has been marked as rollback-only");}processCommit(defStatus);}
上面這段代碼就是transactionmanager中的commit,但是看上去,它又把自己的職責(zé)分配給別人了,從代碼里我們看到,如果事務(wù)已經(jīng)結(jié)束了就拋異常,如果事務(wù)是rollbackonly的,那么就rollback吧,但是按照正常流程,我們還是想來看一下,事務(wù)的提交,就是processCommit(status)這個(gè)方法吧。
- private void processCommit(DefaultTransactionStatus status) throws TransactionException {
- try {
- boolean beforeCompletionInvoked = false;
- try {
- triggerBeforeCommit(status);
- triggerBeforeCompletion(status);
- beforeCompletionInvoked = true;
- if (status.hasSavepoint()) {
- if (status.isDebug()) {
- logger.debug("Releasing transaction savepoint");
- }
- status.releaseHeldSavepoint();
- }
- else if (status.isNewTransaction()) {
- if (status.isDebug()) {
- logger.debug("Initiating transaction commit");
- }
- boolean globalRollbackOnly = status.isGlobalRollbackOnly();
- doCommit(status);
-
-
- `````````````````````
- }
private void processCommit(DefaultTransactionStatus status) throws TransactionException {try {boolean beforeCompletionInvoked = false;try {triggerBeforeCommit(status);triggerBeforeCompletion(status);beforeCompletionInvoked = true;if (status.hasSavepoint()) {if (status.isDebug()) {logger.debug("Releasing transaction savepoint");}status.releaseHeldSavepoint();}else if (status.isNewTransaction()) {//這個(gè)判斷非常重要,下面會(huì)詳細(xì)講解這個(gè)判斷的作用if (status.isDebug()) {logger.debug("Initiating transaction commit");}boolean globalRollbackOnly = status.isGlobalRollbackOnly();doCommit(status);// Throw UnexpectedRollbackException if we have a global rollback-only// marker but still didn't get a corresponding exception from commit.`````````````````````}
我們注意到,在判斷一個(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è)方法好像沒有這么貼切,廢話少說,我們來看一下吧:
- private TransactionStatus handleExistingTransaction(
- TransactionDefinition definition, Object transaction, boolean debugEnabled)
- throws TransactionException {
-
- if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
- throw new IllegalTransactionStateException(
- "Transaction propagation 'never' but existing transaction found");
- }
-
- if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
- if (debugEnabled) {
- logger.debug("Suspending current transaction");
- }
- Object suspendedResources = suspend(transaction);
- boolean newSynchronization = (this.transactionSynchronization == SYNCHRONIZATION_ALWAYS);
- return newTransactionStatus(
- definition, null, false, newSynchronization, debugEnabled, suspendedResources);
- }
-
- if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
- if (debugEnabled) {
- logger.debug("Suspending current transaction, creating new transaction with name [" +
- definition.getName() + "]");
- }
- Object suspendedResources = suspend(transaction);
- doBegin(transaction, definition);
- boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);
- return newTransactionStatus(
- definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
- }
-
- 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()) {
-
-
-
- DefaultTransactionStatus status =
- newTransactionStatus(definition, transaction, false, false, debugEnabled, null);
- status.createAndHoldSavepoint();
- return status;
- }
- else {
-
-
-
- doBegin(transaction, definition);
- boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);
- return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);
- }
- }
-
-
- if (debugEnabled) {
- logger.debug("Participating in existing transaction");
- }
- boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);
- return newTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
- }
private TransactionStatus handleExistingTransaction(TransactionDefinition definition, Object transaction, boolean debugEnabled)throws TransactionException {if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {throw new IllegalTransactionStateException("Transaction propagation 'never' but existing transaction found");}if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {if (debugEnabled) {logger.debug("Suspending current transaction");}Object suspendedResources = suspend(transaction);boolean newSynchronization = (this.transactionSynchronization == SYNCHRONIZATION_ALWAYS);return newTransactionStatus(definition, null, false, newSynchronization, debugEnabled, suspendedResources);}if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {if (debugEnabled) {logger.debug("Suspending current transaction, creating new transaction with name [" +definition.getName() + "]");}Object suspendedResources = suspend(transaction);doBegin(transaction, definition);boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);}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 =newTransactionStatus(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.doBegin(transaction, definition);boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);return newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, null);}}// Assumably PROPAGATION_SUPPORTS.if (debugEnabled) {logger.debug("Participating in existing transaction");}boolean newSynchronization = (this.transactionSynchronization != SYNCHRONIZATION_NEVER);return newTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);}
我們看到這個(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)作:
- else if (status.isNewTransaction()) {
- if (status.isDebug()) {
- logger.debug("Initiating transaction commit");
- }
- boolean globalRollbackOnly = status.isGlobalRollbackOnly();
- doCommit(status);
- }
else if (status.isNewTransaction()) {//這個(gè)判斷非常重要,下面會(huì)詳細(xì)講解這個(gè)判斷的作用if (status.isDebug()) {logger.debug("Initiating transaction commit");}boolean globalRollbackOnly = status.isGlobalRollbackOnly();doCommit(status);}
也就是說在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í)在是讓大家的眼睛受罪了。