Spring的事物管理

1、事物的定義和特性java

事物表明的是一個操做集合。也就是一連串的操做爲一個最小單元不可分割(原子性),這一連串的操做要麼所有成功要不所有失敗(一致性),每個操做集合互不干擾(隔離性),操做集合的全部操做完成後數據必須以一種持久性方式存儲起來(持久性)。spring

 

2、Spring的事務管理express

Spring的事務管理分爲編程式事物和聲明式事物。編程

一、編程式事物管理框架

   基於底層API的編程式事物管理學習

   根據PlateformTransactionManger、TransactionDefinition和TransactionStatus這三個核心接口完成 編程式事物管理。編碼

基於底層API的事物管理代碼示例spa

1 public class BankServiceImpl implements BankService {
 2 private BankDao bankDao;
 3 private TransactionDefinition txDefinition;
 4 private PlatformTransactionManager txManager;
 5 ......
 6 public boolean transfer(Long fromId, Long toId, double amount) {
 7     TransactionStatus txStatus = txManager.getTransaction(txDefinition);
 8     boolean result = false;
 9 try {
10     result = bankDao.transfer(fromId, toId, amount);
11     txManager.commit(txStatus);
12     } catch (Exception e) {
13         result = false;
14         txManager.rollback(txStatus);
15         System.out.println("Transfer Error!");
16     }
17     return result;
18 }
19 }

基於底層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>

基於TransactionTemplate的編程式事物管理code

這種是上面的簡化版

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;
    }
});
}
}

配置文件示例

<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 的聲明式事務管理在底層是創建在 AOP 的基礎之上的。其本質是對方法先後進行攔截,而後在目標方法開始以前建立或者加入一個事務,在執行完目標方法以後根據執行狀況提交或者回滾事務。

聲明式事務最大的優勢就是不須要經過編程的方式管理事務,這樣就不須要在業務邏輯代碼中摻瑣事務管理的代碼,只需在配置文件中作相關的事務規則聲明(或經過等價的基於標註的方式),即可以將事務規則應用到業務邏輯中。由於事務管理自己就是一個典型的橫切邏輯,正是 AOP 的用武之地。Spring 開發團隊也意識到了這一點,爲聲明式事務提供了簡單而強大的支持。

聲明式事務管理曾經是 EJB 引覺得傲的一個亮點,現在 Spring 讓 POJO 在事務管理方面也擁有了和 EJB 同樣的待遇,讓開發人員在 EJB 容器以外也用上了強大的聲明式事務管理功能,這主要得益於 Spring 依賴注入容器和 Spring AOP 的支持。依賴注入容器爲聲明式事務管理提供了基礎設施,使得 Bean 對於 Spring 框架而言是可管理的;而 Spring AOP 則是聲明式事務管理的直接實現者,這一點經過清單8能夠看出來。

一般狀況下,筆者強烈建議在開發中使用聲明式事務,不只由於其簡單,更主要是由於這樣使得純業務代碼不被污染,極大方便後期的代碼維護。

和編程式事務相比,聲明式事務惟一不足地方是,後者的最細粒度只能做用到方法級別,沒法作到像編程式事務那樣能夠做用到代碼塊級別。可是即使有這樣的需求,也存在不少變通的方法,好比,能夠將須要進行事務管理的代碼塊獨立爲方法等等。

下面就來看看 Spring 爲咱們提供的聲明式事務管理功能。

基於 TransactionInter... 的聲明式事務管理

Spring 提供了 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>

基於 TransactionProxy... 的聲明式事務管理

<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>

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

前面兩種聲明式事務配置方式奠基了 Spring 聲明式事務管理的基石。在此基礎上,Spring 2.x 引入了 <tx> 命名空間,結合使用 <aop> 命名空間,帶給開發人員配置聲明式事務的全新體驗,配置變得更加簡單和靈活。另外,得益於 <aop> 命名空間的切點表達式支持,聲明式事務也變得更增強大。

<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>

若是默認的事務屬性就能知足要求,那麼代碼簡化爲

<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 方法將都具備該類型的事務屬性,同時,咱們也能夠在方法級別使用該標註來覆蓋類級別的定義。

@Transactional(propagation = Propagation.REQUIRED)
public boolean transfer(Long fromId, Long toId, double amount) {
return bankDao.transfer(fromId, toId, amount);
}

Spring 使用 BeanPostProcessor 來處理 Bean 中的標註,所以咱們須要在配置文件中做以下聲明來激活該後處理 Bean

啓用處理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 指定事務規則便可實現事務管理,並且功能也沒必要其餘方式遜色。
相關文章
相關標籤/搜索