Spring編程式事務管理及聲明式事務管理

Spring 事務屬性剖析

事務治理對企業運用而言至關主要。它擔保了用戶的每次操作都是靠得住的,即便泛起了異常的接見情形,也不至於損壞後臺數據的完整性。就像銀行的自助 取款機,常日都能正常爲客戶幹事,然則也難免碰着操作進程傍邊機械溘然出缺點的情形,此時,事務就必需確保出缺點前對賬戶的操作不生效,就像用戶適才完整 沒有行使過取款機一樣,以擔保用戶和銀行的優點都不受損丟失落。

在 Spring 中,事務是經由進程 TransactionDefinition 接口來界說的。該接口包括與事務屬性有關的方法。具體如清單1所示:

清單1. TransactionDefinition 接口中界說的次要方法
public interface TransactionDefinition{
int getIsolationLevel();
int getPropagationBehavior();
int getTimeout();
boolean isReadOnly();
}

也許你會希奇,爲什麼接口只供應了獲得屬性的方法,而沒有供應相關設置屬性的方法。其實事理很龐雜,事務屬性的設置完整是軌範員掌握的,是以軌範員 可以自界說任何設置屬性的方法,而且留存屬性的字段也沒有任何要求。獨一的要求的是,Spring 中止事務操作的時辰,經由進程挪用以上接口供給的方法必需可以前舊事務相關的屬性取值。

事務隔離級別

隔離級別是指若干個併發的事務之間的隔離水平。TransactionDefinition 接口中界說了五個泄漏表現隔離級其他常量:

  • TransactionDefinition.ISOLATION_DEFAULT:這是默許值,泄漏表現行使底層數據庫的默許隔離級別。對除夜部份數據 庫而言,常日這值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED:該隔離級別泄漏表現一個事務可以讀取其他一個事務改削但還沒有提交的數據。該級別不能避免髒讀和弗成重複讀,是以很少行使該隔離級別。
  • TransactionDefinition.ISOLATION_READ_COMMITTED:該隔離級別泄漏表現一個事務只能讀取其他一個事務已提交的數據。該級別可以避免髒讀,這也是除夜多半情形下的舉薦值。
  • TransactionDefinition.ISOLATION_REPEATABLE_READ:該隔離級別泄漏表現一個事務在悉數進程傍邊可以多次 重複實行某個查詢,而且每次前往的記載都溝通。即便在多次查詢之間有新增的數據知足該查詢,這些新增的記載也會被疏忽。該級別可以避免髒讀和弗成重複讀。
  • TransactionDefinition.ISOLATION_SERIALIZABLE:一切的事務順次一一實行,這樣事務之間就完整弗成能發生發火煩擾,也就是說,該級別可以避免髒讀、弗成重複讀和幻讀。然則這將嚴重影響軌範的功效。常日情形下也不會用到該級別。

事務流傳舉動

所謂事務的流傳舉動是指,假定在最先當前事務之前,一個事務高下文已存在,此時有若干選項可以指定一個事務性方法的執步履作。在TransactionDefinition界說中包括了以下幾個泄漏表現流傳舉動的常量:

  • TransactionDefinition.PROPAGATION_REQUIRED:假定當前存在事務,則介入該事務;假定當前沒有事務,則樹立一個新的事務。
  • TransactionDefinition.PROPAGATION_REQUIRES_NEW:樹立一個新的事務,假定當前存在事務,則把當前事務掛起。
  • TransactionDefinition.PROPAGATION_SUPPORTS:假定當前存在事務,則介入該事務;假定當前沒有事務,則以非事務的體式格式連續運轉。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務體式格式運轉,假定當前存在事務,則把當前事務掛起。
  • TransactionDefinition.PROPAGATION_NEVER:以非事務體式格式運轉,假定當前存在事務,則拋出異常。
  • TransactionDefinition.PROPAGATION_MANDATORY:假定當前存在事務,則介入該事務;假定當前沒有事務,則拋出異常。
  • TransactionDefinition.PROPAGATION_NESTED:假定當前存在事務,則樹立一個事務作爲當前事務的嵌套事務來運轉; 假定當前沒有事務,則該取值等價於TransactionDefinition.PROPAGATION_REQUIRED。

這裏需求指出的是,後面的六種事務流傳舉動是 Spring 從 EJB 中引入的,他們同享溝通的概念。而 PROPAGATION_NESTED是 Spring 所獨有的。以 PROPAGATION_NESTED 啓動的事務內嵌於內部事務中(假定存在內部事務的話),此時,內嵌事務並非一個自力的事務,它依託於內部事務的存在,只需經由進程內部的事務提交,才華激 起內部事務的提交,嵌套的子事務不能零丁提交。假定熟習 JDBC 中的留存點(SavePoint)的概念,那嵌套事務就很隨意疏忽理解了,其實嵌套的子事務就是留存點的一個運用,一個事務中可以包括多個留存點,每一個 嵌套子事務。其他,內部事務的回滾也會致使嵌套子事務的回滾。

事務超時

所謂事務超時,就是指一個事務所准許實行的最長時辰,假定跨越該時辰限制但事務還沒有完成,則自動回滾事務。在 TransactionDefinition 中以 int 的值來泄漏表現超不時辰,其單元是秒。

事務的只讀屬性

事務的只讀屬性是指,對事務性成本中止只讀操作或是讀寫操作。所謂事務性成本就是指那些被事務治理的成本,好比數據源、 JMS 成本,和自界說的事務性成本等等。假定一定只對事務性成本中止只讀操作,那末我們可以將事務符號爲只讀的,以提高事務處置責罰的功效。在 TransactionDefinition 中以 boolean 類型來泄漏表現該事務能否是隻讀。

事務的回滾劃定禮貌

常日情形下,假定在事務中拋出了未搜檢異常(連續自 RuntimeException 的異常),則默許將回滾事務。假定沒有拋出任何異常,或拋出了已搜檢異常,則仍然提交事務。這常日也是除夜多半墾荒者進展的處置責罰體式格式,也是 EJB 中的默許處置責罰體式格式。然則,我們可以憑證需求工資掌握事務在拋出某些未搜檢異常時任然提交事務,或在拋出某些已搜檢異常時回滾事務。


Spring 事務治理 API 剖析

Spring 框架中,觸及到事務治理的 API 除夜約有100個旁邊,箇中最主要的有三個:TransactionDefinition、PlatformTransactionManager、 TransactionStatus。所謂事務治理,其實就是“依照給定的事務劃定禮貌來實行提交或回滾操作”。“給定的事務劃定禮貌”就是用 TransactionDefinition 泄漏表現的,“依照……來實行提交或回滾操作”就是用 PlatformTransactionManager 來泄漏表現,而 TransactionStatus 用於泄漏表現一個運轉着的事務的形態。打一個不適合的歧,TransactionDefinition 與 TransactionStatus 的關係就像軌範和進程的關係。

TransactionDef…

該接口在後面已引見過,它用於界說一個事務。它包括了事務的靜態屬性,好比:事務流傳舉動、超不時辰等等。Spring 爲我們供應了一個默許的完成類:DefaultTransactionDefinition,該類適用於除夜多半情形。假定該類不能知足需求,可以經由進 程完成 TransactionDefinition 接口來完成本人的事務界說。

PlatformTrans…

PlatformTransactionManager 用於實行具體的事務操作。接口界說如清單2所示:

清單2. PlatformTransactionManager 接口中界說的次要方法
Public interface PlatformTransactionManager{
  TransactionStatus getTransaction(TransactionDefinition definition)
   throws TransactionException;
   void commit(TransactionStatus status)throws TransactionException;
   void rollback(TransactionStatus status)throws TransactionException;
}

憑證底層所行使的不合的經久化 API 或框架,PlatformTransactionManager 的次要完成類除夜致以下:

  • DataSourceTransactionManager:適用於行使JDBC和iBatis中止數據經久化操作的情形。
  • HibernateTransactionManager:適用於行使Hibernate中止數據經久化操作的情形。
  • JpaTransactionManager:適用於行使JPA中止數據經久化操作的情形。
  • 其他還有JtaTransactionManager 、JdoTransactionManager、JmsTransactionManager等等。

假定我們行使JTA中止事務治理,我們可以經由進程 JNDI 和 Spring 的 JtaTransactionManager 來獲得一個容器治理的 DataSource。JtaTransactionManager 不需求曉得 DataSource 和其他特定的成本,因爲它將行使容器供應的全局事務治理。而對其他事務治理器,好比DataSourceTransactionManager,在界說時 需求供應底層的數據源作爲其屬性,也就是 DataSource。與 HibernateTransactionManager 對應的是 SessionFactory,與 JpaTransactionManager 對應的是 EntityManagerFactory 等等。

TransactionStatus

PlatformTransactionManager.getTransaction(…) 方法前往一個 TransactionStatus 對象。前往的TransactionStatus 對象可以代表一個新的或已存在的事務(假定在當前挪用客棧有一個相符前提的事務)。TransactionStatus 接口供給了一個龐雜的掌握事務實行和查詢事務形態的方法。該接口界說如清單3所示:

清單3. TransactionStatus 接口中界說的次要方法
public  interface TransactionStatus{
   boolean isNewTransaction();
   void setRollbackOnly();
   boolean isRollbackOnly();
}

編程式事務治理

Spring 的編程式事務治理概述

在 Spring 泛起之前,編程式事務治理對基於 POJO 的運用來說是獨一選擇。用過 Hibernate 的人都曉得,我們需求在代碼中顯式挪用beginTransaction()、commit()、rollback()等事務治理相關的方法,這就是編程 式事務治理。經由進程 Spring 供應的事務治理 API,我們可以在代碼中無邪掌握事務的實行。在底層,Spring 仍然將事務操作請託給底層的經久化框架來實行。

基於底層 API 的編程式事務治理

憑證PlatformTransactionManager、TransactionDefinition 和 TransactionStatus 三個焦點接口,我們完整可以經由進程編程的體式格式來中止事務治理。示例代碼如清單4所示:

清單4. 基於底層 API 的事務治理示例代碼
public class BankServiceImpl implements BankService {
private BankDao bankDao;
private TransactionDefinition txDefinition;
private PlatformTransactionManager txManager;
......
public boolean transfer(Long fromId, Long toId, double amount) {
TransactionStatus txStatus = txManager.getTransaction(txDefinition);
boolean result = false;
try {
result = bankDao.transfer(fromId, toId, amount);
txManager.commit(txStatus);
} catch (Exception e) {
result = false;
txManager.rollback(txStatus);
System.out.println("Transfer Error!");
}
return result;
}
}

呼應的設置配備鋪排文件如清單5所示:

清單5. 基於底層API的事務治理示例設置配備鋪排文件
<bean id="bankService" class="footmark.spring.core.tx.programmatic.origin.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
<property name="txManager" ref="transactionManager"/>
<property name="txDefinition">
<bean class="org.springframework.transaction.support.DefaultTransactionDefinition">
<property name="propagationBehaviorName" value="PROPAGATION_REQUIRED"/>
</bean>
</property>
</bean>

如上所示,我們在類中增加了兩個屬性:一個是 TransactionDefinition 類型的屬性,它用於界說一個事務;其他一個是 PlatformTransactionManager 類型的屬性,用於實行事務治理操作。

假定方法需求實行事務治理,我們首先需求在方法最先實行前啓動一個事務,挪用 PlatformTransactionManager.getTransaction(…) 方法即可啓動一個事務。樹立並啓動了事務之後,即可以最先編寫營業邏輯代碼,然後在適合的地方實行事務的提交或回滾。

基於 TransactionTemplate 的編程式事務治理

經由進程後面的示例可以發明,這類事務治理體式格式很隨意疏忽理解,但使人頭疼的是,事務治理的代碼散落在營業邏輯代碼中,損壞了原有代碼的條感 性,而且每一個營業方法都包括了相反的啓動事務、提交/回滾事務的樣板代碼。幸而,Spring 也意想到了這些,並供應了簡化的方法,這就是 Spring 在數據接見層異經罕有的模板回調方法。如清單6所示:

清單6. 基於 TransactionTemplate 的事務治理示例代碼
public class BankServiceImpl implements BankService {
private BankDao bankDao;
private TransactionTemplate transactionTemplate;
......
public boolean transfer(final Long fromId, final Long toId, final double amount) {
return (Boolean) transactionTemplate.execute(new TransactionCallback(){
public Object doInTransaction(TransactionStatus status) {
Object result;
try {
result = bankDao.transfer(fromId, toId, amount);
} catch (Exception e) {
status.setRollbackOnly();
result = false;
System.out.println("Transfer Error!");
}
return result;
}
});
}
}

呼應的XML設置配備鋪排以下:

清單 7. 基於 TransactionTemplate 的事務治理示例設置配備鋪排文件
<bean id="bankService"
class="footmark.spring.core.tx.programmatic.template.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
<property name="transactionTemplate" ref="transactionTemplate"/>
</bean>

TransactionTemplate 的 execute() 方法有一個 TransactionCallback 類型的參數,該接口中界說了一個 doInTransaction() 方法,常日我們以匿名內部類的體式格式完成 TransactionCallback 接口,並在其 doInTransaction() 方法中書寫營業邏輯代碼。這裏可以行使默許的事務提交和回滾劃定禮貌,這樣在營業代碼中就不需求顯式挪用任何事務治理的 API。doInTransaction() 方法有一個TransactionStatus 類型的參數,我們可以在方法的任何位置挪用該參數的 setRollbackOnly() 方法將事務標識爲回滾的,以實行事務回滾。

憑證默許劃定禮貌,假定在實行回調方法的進程傍邊拋出了未搜檢異常,或顯式挪用了TransacationStatus.setRollbackOnly() 方法,則回滾事務;假定事務實行完成或拋出了 checked 類型的異常,則提交事務。

TransactionCallback 接口有一個子接口 TransactionCallbackWithoutResult,該接口中界說了一個 doInTransactionWithoutResult() 方法,TransactionCallbackWithoutResult 接口次要用於事務進程傍邊不需求前往值的情形。雖然,對不需求前往值的情形,我們仍然可以行使 TransactionCallback 接口,並在方法中前往隨意率性值即可。


聲明式事務治理

Spring 的聲明式事務治理概述

Spring 的聲明式事務治理在底層是豎立在 AOP 的根蒂根抵之上的。其實質是對方法前落先行隔絕,然後在目的方法最先之前樹立或介入一個事務,在實行完目的方法之後憑證實行情形提交或回滾事務。

聲明式事務最除夜的優點就是不需求經由進程編程的體式格式治理事務,這樣就不需求在營業邏輯代碼中攙雜事務治理的代碼,只需在設置配備鋪排文件中做 相關的事務劃定禮貌聲明(或經由進程等價的基於標註的體式格式),即可以將事務劃定禮貌運用到營業邏輯中。因爲事務治理本人就是一個範例的橫切邏輯,恰是 AOP 的用武之地。Spring 墾荒團隊也意想到了這一點,爲聲明式事務供應了龐雜而丁壯夜的支持。

聲明式事務治理曾是 EJB 引以爲傲的一個亮點,現在 Spring 讓 POJO 在事務治理方面也具有了和 EJB 一樣的待遇,閃墾荒人員在 EJB 容器之外也用上了丁壯夜的聲明式事務治理功用,此次要得益於 Spring 依託注入容器和 Spring AOP 的支持。依託注入容器爲聲明式事務治理供應了根蒂根抵舉動裝備,使得 Bean 對 Spring 框架而言是可治理的;而 Spring AOP 則是聲明式事務治理的直接完成者,這一點經由進程清單8可以看出來。

常日情形下,筆者劇烈建議在墾荒中行使聲明式事務,不只因爲其龐雜,更主假定因爲這樣使得純營業代碼不被淨化,極除夜隨意後期的代碼珍重。

和編程式事務比照,聲明式事務獨一缺少地方是,後者的最細粒度只能浸染到方法級別,沒法做到像編程式事務那樣可以浸染到代碼塊級別。然則即便有這樣的需求,也存在許多變通的方法,好比,可以將需求中止事務治理的代碼塊自力爲方法等等。

上面就來看看 Spring 爲我們供應的聲明式事務治理功用。

基於 TransactionInter… 的聲明式事務治理

最初,Spring 供應了 TransactionInterceptor 類來實行聲明式事務治理功用。先看清單8的設置配備鋪排文件:

清單 8. 基於 TransactionInterceptor 的事務治理示例設置配備鋪排文件
<beans...>
......
<bean id="transactionInterceptor"
class="org.springframework.transaction.interceptor.TransactionInterceptor">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="transfer">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
<bean id="bankServiceTarget"
class="footmark.spring.core.tx.declare.origin.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
</bean>
<bean id="bankService"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="bankServiceTarget"/>
<property name="interceptorNames">
<list>
<idref bean="transactionInterceptor"/>
</list>
</property>
</bean>
......
</beans>

首先,我們設置配備鋪排了一個 TransactionInterceptor 來界說相關的事務劃定禮貌,他有兩個次要的屬性:一個是 transactionManager,用來指定一個事務治理器,並將具體事務相關的操作請託給它;其他一個是 Properties 類型的 transactionAttributes 屬性,它次要用來界說事務劃定禮貌,該屬性的每一個鍵值對中,鍵指定的是方法名,方法名可以行使通配符,而值就泄漏表現呼應方法的所運用的事務屬性。

指定事務屬性的取值有較龐雜的劃定禮貌,這在 Spring 中算得上是一件讓人頭疼的事。具體的書寫劃定禮貌以下:

流傳舉動 [,隔離級別] [,只讀屬性] [,超時屬性] [不影響提交的異常] [,致使回滾的異常]
  • 流傳舉動是獨一必需設置的屬性,其他都可以疏忽,Spring爲我們供應了合理的默許值。
  • 流傳舉動的取值必需以“PROPAGATION_”開首,具體包括:PROPAGATION_MANDATORY、 PROPAGATION_NESTED、PROPAGATION_NEVER、PROPAGATION_NOT_SUPPORTED、 PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_SUPPORTS,共七種取 值。
  • 隔離級其他取值必需以“ISOLATION_”開首,具體包括:ISOLATION_DEFAULT、 ISOLATION_READ_COMMITTED、ISOLATION_READ_UNCOMMITTED、 ISOLATION_REPEATABLE_READ、ISOLATION_SERIALIZABLE,共五種取值。
  • 假定事務是隻讀的,那末我們可以指定只讀屬性,行使“readOnly”指定。否則我們不需求設置該屬性。
  • 超時屬性的取值必需以“TIMEOUT_”開首,後面跟一個int類型的值,泄漏表現超不時辰,單元是秒。
  • 不影響提交的異常是指,即便事務中拋出了這些類型的異常,事務任然正常提交。必需在每一個異常的名字後面加上“+”。異常的名字可所以類名的一部份。好比“+RuntimeException”、“+tion”等等。
  • 致使回滾的異常是指,當事務中拋出這些類型的異常時,事務將回滾。必需在每一個異常的名字後面加上“-”。異常的名字可所以類名的悉數或部份,好比“-RuntimeException”、“-tion”等等。

以下是兩個示例:

<property name="*Service">
PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED,TIMEOUT_20,
+AbcException,+DefException,-HijException
</property>

以上表達式泄漏表現,針對一切方法名以 Service 收尾的方法,行使 PROPAGATION_REQUIRED 事務流傳舉動,事務的隔離級別是 ISOLATION_READ_COMMITTED,超不時辰爲20秒,當事務拋出 AbcException 或 DefException 類型的異常,則仍然提交,當拋出 HijException 類型的異常時必需回滾事務。這裏沒有指定”readOnly”,泄漏表現事務不是隻讀的。

<property name="test">PROPAGATION_REQUIRED,readOnly</property>

以上表達式泄漏表現,針對一切方法名爲 test 的方法,行使 PROPAGATION_REQUIRED 事務流傳舉動,而且該事務是隻讀的。除此之外,其他的屬性均行使默許值。好比,隔離級別和超不時辰行使底層事務性成本的默許值,而且當發生發火未搜檢異 常,則回滾事務,發生發火已搜檢異常則仍提交事務。

設置配備鋪排好了 TransactionInterceptor,我們還需求設置配備鋪排一個 ProxyFactoryBean 來組裝 target 和advice。這也是範例的 Spring AOP 的做法。經由進程 ProxyFactoryBean 生成的署理類就是織入了事務治理邏輯後的目的類。至此,聲明式事務治理就算是完成了。我們沒有對營業代碼中止任何操作,一切設置均在設置配備鋪排文件中完 成,這就是聲明式事務的最除夜優點。

基於 TransactionProxy… 的聲明式事務治理

後面的聲明式事務雖然好,然則卻存在一個異常惱人的成就:設置配備鋪排文件太多。我們必需針對每一個目的對象設置配備鋪排一個 ProxyFactoryBean;其他,雖然可以經由進程父子 Bean 的體式格式來複用 TransactionInterceptor 的設置配備鋪排,然則理想的複用機率也不高;這樣,加上目的對象本人,每一個營業類可以需求對應三個 <bean/> 設置配備鋪排,跟着營業類的增多,設置配備鋪排文件將會變得越來越重除夜,治理設置配備鋪排文件又成了成就。

爲了減緩這個成就,Spring 爲我們供應了 TransactionProxyFactoryBean,用於將TransactionInterceptor 和 ProxyFactoryBean 的設置配備鋪排合二爲一。如清單9所示:

清單9. 基於 TransactionProxyFactoryBean 的事務治理示例設置配備鋪排文件
<beans......>
......
<bean id="bankServiceTarget"
class="footmark.spring.core.tx.declare.classic.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
</bean>
<bean id="bankService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="target" ref="bankServiceTarget"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="transfer">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
......
</beans>

如斯一來,設置配備鋪排文件與先前比照簡化了許多。我們把這類設置配備鋪排體式格式稱爲 Spring 經典的聲明式事務治理。信任在晚期行使 Spring 的墾荒人員對這類設置配備鋪排聲明式事務的體式格式一定異常熟習。

然則,顯式爲每一個營業類設置配備鋪排一個 TransactionProxyFactoryBean 的做法將使得代碼顯得過於機械,爲此我們可以行使自動樹立署理的體式格式來將其簡化,行使自動樹立署理是純 AOP 常識,請讀者參考相關文檔,不在此贅述。

基於 <tx> 命名空間的聲明式事務治理

後面兩種聲明式事務設置配備鋪排體式格式奠基了 Spring 聲明式事務治理的基石。在此根蒂根抵上,Spring 2.x 引入了 <tx> 命名空間,連絡行使 <aop> 命名空間,帶給墾荒人員設置配備鋪排聲明式事務的全新體驗,設置配備鋪排變得加倍龐雜和無邪。其他,得益於 <aop> 命名空間的切點表達式支持,聲明式事務也變得加倍丁壯夜。

如清單10所示:

清單10. 基於 <tx> 的事務治理示例設置配備鋪排文件
<beans......>
......
<bean id="bankService" 
class="footmark.spring.core.tx.declare.namespace.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
</bean>
<tx:advice id="bankAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transfer" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>

<aop:config>
<aop:pointcut id="bankPointcut" expression="execution(* *.transfer(..))"/>
<aop:advisor advice-ref="bankAdvice" pointcut-ref="bankPointcut"/>
</aop:config>
......
</beans>

假定默許的事務屬性就可以知足要求,那末代碼簡化爲如清單 11 所示:

清單 11. 簡化後的基於 <tx> 的事務治理示例設置配備鋪排文件
<beans......>
......
<bean id="bankService"
class="footmark.spring.core.tx.declare.namespace.BankServiceImpl">
<property name="bankDao" ref="bankDao"/>
</bean>
<tx:advice id="bankAdvice" transaction-manager="transactionManager">
<aop:config>
<aop:pointcut id="bankPointcut" expression="execution(**.transfer(..))"/>
<aop:advisor advice-ref="bankAdvice" pointcut-ref="bankPointcut"/>
</aop:config>
......
</beans>

因爲行使了切點表達式,我們就不需求針對每一個營業類樹立一個署理對象了。其他,假定設置配備鋪排的事務治理器 Bean 的名字取值爲“transactionManager”,則我們可以省略 <tx:advice> 的 transaction-manager 屬性,因爲該屬性的默許值即爲“transactionManager”。

基於 @Transactional 的聲明式事務治理

除基於命名空間的事務設置配備鋪排體式格式,Spring 2.x 還引入了基於 Annotation 的體式格式,具體次要觸及@Transactional 標註。@Transactional 可以浸染於接口、接口方法、類和類方法上。算作用於類上時,該類的一切 public 方法將都具有該類型的事務屬性,同時,我們也可以在方法級別行使該標註來籠蓋類級其他界說。如清單12所示:

清單12. 基於 @Transactional 的事務治理示例設置配備鋪排文件
@Transactional(propagation = Propagation.REQUIRED)
public boolean transfer(Long fromId, Long toId, double amount) {
return bankDao.transfer(fromId, toId, amount);
}

Spring 行使 BeanPostProcessor 來處置責罰 Bean 中的標註,是以我們需求在設置配備鋪排文件中作以下聲明來激活該後處置責罰 Bean,如清單13所示:

清單13. 啓用後處置責罰Bean的設置配備鋪排
<tx:annotation-driven transaction-manager="transactionManager"/>

與後面相反,transaction-manager 屬性的默許值是 transactionManager,假定事務治理器 Bean 的名字即爲該值,則可以省略該屬性。

雖然 @Transactional 註解可以浸染於接口、接口方法、類和類方法上,然則 Spring 小組建議不要在接口或接口方法下行使該註解,因爲這隻需外行使基於接口的署理時它纔會生效。其他, @Transactional 註解理應只被運用到 public 方法上,這是由 Spring AOP 的實質決意的。假定你在 protected、private 或默准許見性的方法下行使 @Transactional 註解,這將被疏忽,也不會拋出任何異常。

基於 <tx> 命名空間和基於 @Transactional 的事務聲明體式格式各有優瑕玷。基於 <tx> 的體式格式,其優點是與切點表達式連絡,功用丁壯夜。行使切點表達式,一個設置配備鋪排可以婚配多個方法,而基於 @Transactional 的體式格式必需在每一個需求行使事務的方法或類上用 @Transactional 標註,雖然可以除夜多半事務的劃定禮貌是不合的,然則對 @Transactional 而言,也沒法重用,必需一一指定。其他一方面,基於 @Transactional 的體式格式行使起來異常龐雜清晰了了,沒有進修成本。墾荒人員可以憑證需求,任選個中一種行使,甚至也可以憑證需求夾雜行使這兩種體式格式。

假定不是對遺留代碼中止珍重,則不建議再行使基於 TransactionInterceptor 和基於TransactionProxyFactoryBean 的聲明式事務治理體式格式,然則,進修這兩種體式格式異常無益於對底層完成的理解。

雖然上面共枚舉了四種聲明式事務治理體式格式,然則這樣的劃分只是爲了便於理解,其實後臺的完成體式格式是一樣的,只是用戶行使的體式格式不合而已。


停止語

本教程的常識點除夜致總結以下:

  • 基於 TransactionDefinition、PlatformTransactionManager、TransactionStatus 編程式事務治理是 Spring 供應的最原始的體式格式,常日我們不會這麼寫,然則意見這類體式格式對理解 Spring 事務治理的實質有很鴻文用。
  • 基於 TransactionTemplate 的編程式事務治理是對上一種體式格式的封裝,使得編碼更龐雜、了了。
  • 基於 TransactionInterceptor 的聲明式事務是 Spring 聲明式事務的根蒂根抵,常日也不建議行使這類體式格式,然則與後面一樣,意見這類體式格式對理解 Spring 聲明式事務有很鴻文用。
  • 基於 TransactionProxyFactoryBean 的聲明式事務是上中體式格式的改良版本,簡化的設置配備鋪排文件的書寫,這是 Spring 晚期舉薦的聲明式事務治理體式格式,然則在 Spring 2.0 中已不舉薦了。
  • 基於 <tx> 和 <aop> 命名空間的聲明式事務治理是今朝舉薦的體式格式,其最除夜特色是與 Spring AOP 連絡慎密,可以富餘行使切點表達式的丁壯夜支持,使得治理事務加倍無邪。
  • 基於 @Transactional 的體式格式將聲明式事務治理簡化到了極致。墾荒人員只需在設置配備鋪排文件中加上一行啓用相關後處置責罰 Bean 的設置配備鋪排,然後在需求實行事務治理的方法或類下行使 @Transactional 指定事務劃定禮貌即可完成事務治理,而且功用也沒需求其他體式格式減色。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章