程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Spring事務探索

Spring事務探索

編輯:關於JAVA

Spring自建事務管理模塊。而且這個事務管理是一個抽象設計,可以應用到很多場合,包括普通的DataSource,jta,jms和hibernate上。

要正確使用spring的事務,首先需要了解spring在事務設計上的一些概念

統觀spring事務,圍繞著兩個核心PlatformTransactionManager和TransactionStatus

PlatformTransactionManager直譯過來就是平台相關事務,這裡的平台指的是“事務源”,包括剛才我說的DataSource,jta等等。這些無一不是一個事務源。廣義的說,凡是可以完成事務性操作的對象,都可以設計出相對應的PlatformTransactionManager,只要這個事務源支持commit,rollback和getTransaction語意。

查看spring代碼,可以發現這些manager實現事務,就是調用事務源的事務操作方法

比如

HibernateTransactionManager

代碼

protected void doCommit(DefaultTransactionStatus status) ...{
     HibernateTransactionObject txObject = (HibernateTransactionObject)
status.getTransaction();
     if (status.isDebug()) ...{
       logger.debug("Committing Hibernate transaction on session [" +
           txObject.getSessionHolder().getSession() + "]");
     }
     try ...{
       txObject.getSessionHolder().getTransaction().commit();
     }
...
   }
jdbc 的DataSourceTransactionManager

代碼

protected void doCommit(DefaultTransactionStatus status) ...{
     DataSourceTransactionObject txObject = (DataSourceTransactionObject)
status.getTransaction();
     Connection con = txObject.getConnectionHolder().getConnection();
     if (status.isDebug()) ...{
       logger.debug("Committing JDBC transaction on connection [" + con
+ "]");
     }
     try ...{
       con.commit();
     }
     ...
   }

那麼PlatformTransactionManager以什麼依據處理事務呢?

是TransactionStatus

查看api發現這個接口有三個方法

isNewTransaction() ,isRollbackOnly(),setRollbackOnly()

PlatformTransactionManager就是根據前兩個方法決定是否要創建一個新事務,是要遞交還是回滾。至於第三個方法是改變事務當前狀態的,很多地方都要用到,偏偏PlatformTransactionManager自身好像不怎麼用,畢竟事務狀態的改變是由程序員代碼決定的,不需要一個manager多管閒事。

總結上面所說的,spring的事務由PlatformTransactionManager管理,manager最後調用事務源的方法來實現一個事務過程。而manager通過TransactionStatus 來決定如何實現。

接下去說spring事務中的TransactionTemplate和TransactionInterceptor

TransactionTemplate其實和spring中其他的template的作用類似,起到化簡代碼的作用,不要被它那麼長的名字嚇倒了,事實上這個template並不是什麼非常核心的對象。如果比較學究派的,可以去看看template設計模式,在此就不再對此贅述了。

為什麼要有TransactionTemplate?先來看看如果沒有TransactionTemplate,我們的代碼該怎麼寫

先來看看spring reference中的一段代碼

代碼

DefaultTransactionDefinition def = new DefaultTransactionDefinition()
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
try ...{
   // execute your business logic here 
} catch (MyException ex) ...{
   transactionManager.rollback(status);
   throw ex;
}
transactionManager.commit(status);

這是直接使用transactionManager的例子,可以看到真正執行business logic 的地方是在try當中那段,前後的代碼都是為了完成事務管理的。如果每個business logic都要寫上那麼一段,我肯定是瘋了。我們翻出TransactionTemplate的代碼看看他怎麼化簡了我們的代碼

代碼

public Object execute(TransactionCallback action) throws TransactionException ...{
     TransactionStatus status = this.transactionManager.getTransaction(this);
     Object result = null;
     try ...{
       result = action.doInTransaction(status);
     }
     catch (RuntimeException ex) ...{
       // transactional code threw application exception -> rollback
       rollbackOnException(status, ex);
       throw ex;
     }
     catch (Error err) ...{
       // transactional code threw error -> rollback
       rollbackOnException(status, err);
       throw err;
     }
     this.transactionManager.commit(status);
     return result;
   }

同上面的代碼如出一轍,前後是事務處理代碼,當中那段result = action.doInTransaction(status);是我們的應用代碼。至於action是什麼,全看各位的需要了。但是有一點要主要,如果利用TransactionTemplate,那麼他不管你扔出什麼異常都會回滾事務,但是回滾的是哪個事務呢?繼續挖代碼

代碼

private void rollbackOnException(TransactionStatus status, Throwable ex) throws
TransactionException ...{
     if (logger.isDebugEnabled()) ...{
       logger.debug("Initiating transaction rollback on application
exception", ex); 
     }
     try ...{
       this.transactionManager.rollback(status);
     }
     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;
     }
   }

真相大白,是對template所持有的某個transactionManager進行回滾。所以如果你的應用代碼用的是事務源a的一些資源,比如到服務器a的一個datasource,但是你的transactionManager管理的是另一些資源,比如服務器b的一個datasource,代碼鐵定不會正常運行

特別是在一些多事務源的程序裡,這點千萬不能搞錯。如果多個事務源之間要完成全局事務,還是老老實實用分布式事務管理服務吧(jta)

那麼TransactionInterceptor是干什麼的?這個是spring 的聲明式事務的支持方式。因為用TransactionTemplate要硬編碼,而且調整事務策略很麻煩(不是說不能調。舉個例子原來程序拋出異常A需要回滾,現在不需要要,我就可以把a catch吃掉。這時候template就不會回滾了。但是每次調整都要重寫編碼。)而用TransactionInterceptor就可以將這些調整寫在配置中。我們再來挖TransactionInterceptor的代碼

代碼

public Object invoke(MethodInvocation invocation) throws Throwable ...{
     // Work out the target class: may be null.
     // The TransactionAttributeSource should be passed the target class
     // as well as the method, which may be from an interface 
     Class targetClass = (invocation.getThis() != null) ? 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 exception 
       doCloseTransactionAfterThrowing(txInfo, ex);
       throw ex;
     }
     finally ...{
       doFinally(txInfo);
     }
     doCommitTransactionAfterReturning(txInfo);
     return retVal;
   }

萬變不離其宗。

所以使用spring的事務管理需要作這些事

1,設置好事務源,比如DataSource,hibernate的session。如果有多個事務源要考慮他們之間是否有全局事務,如果有,老老實實用jta,否則就需要自己寫一個manager了

2,設置manager,根據你的事務源選擇對應的PlatformTransactionManager

3,選擇實現事物的方式,用template還是interceptor。用template代碼直觀點,但是template所管轄的manager和你應用代碼所用的事務源要一致。如果用interceptor千萬注意,一定要調用interceptor那個bean,而不是原始的那個target。在壇子上我已經看到至少有兩個朋友說spring事物不起作用,從配置和代碼上看都正確,這時要好好查查,調用的bean是哪一個。

4,這個是設計問題了,推薦事務處於一個較高層次,比如service上的某個函數,而底層的dao可以不考慮事務,否則可能會出現事務嵌套,增加程序復雜度。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved