Spring事務——Spring 2.X的事務配置策略

Spring 2.X的事務配置策略java

    雖然前面介紹的TransactionProxyFactoryBean配置策略簡單易懂,但配置起來極爲麻煩:每一個目標Bean都須要配置一個TransactionProxyFactoryBean代理,這種方式將致使配置文件急劇增長。mysql

    Spring 2.X的XMLSchema方式提供了更簡潔的事務配置策略,Spring 2.X提供了tx命名空間來配置事務管理,tx命名空間提供了<tx:advice../>元素來配置事務加強處理,一旦使用該元素配置了加強處理,就能夠直接使用<aop:advisor../>元素啓用自動代理了。
spring

    下面的應用示例依然使用前面(點擊查看)提供的NewsDao接口和NewsDaoImpl實現類,但改成使用<tx:advice../>元素來配置事務加強處理,再使用<tx:advisor../>爲容器中一批Bean配置自動事務代理。下面是配置文件:
sql

<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
		http://www.springframework.org/schema/aop 
		http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
		http://www.springframework.org/schema/tx 
		http://www.springframework.org/schema/aop/spring-tx-3.0.xsd
		http://www.springframework.org/schema/context
    		http://www.springframework.org/schema/context/spring-context-3.0.xsd">
    		
    <!-- 使用C3P0數據庫鏈接池做爲數據源 -->
    <bean id="dataSource" 
        class="com.mchange.v2.c3p0.ComboPolledDataSource" destroy-method="close">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="jdbc:mysql://localhost/test" />
        <property name="user" value="root" />
        <property name="password" value="root" />
        <property name="maxPoolSize" value="40" />
        <property name="minPoolSize" value="4" />
        <property name="initialPoolSize" value="10" />
        <!-- 指定數據庫鏈接池的鏈接的最大空閒時間 -->
        <property name="maxIdleTime" value="20" />
    </bean>

    <!-- 配置JDBC數據源的局部事務管理器,使用DataSourceTransactionManager類,該類實現了
    PlatformTransactionManager接口,是針對採用數據源鏈接的特定實現 -->
    <bean id="transactionManager" 
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!-- 配置TransactionManager時須要注入數據源引用 -->
        <property name="dataSource" ref="dataSource" />
    </bean>

    <!-- 下面這個是前面定義的業務Bean -->
    <bean id="newsDao" class="com.abc.dao.impl.NewsDaoImpl">
        <!-- 爲業務Bean注入屬性 -->
        <property name="dataSource" ref="dataSource" />
    </bean>
    
    <!-- 配置事務加強處理Bean,指定事務管理器 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!-- 用於配置詳細的事務語義 -->
        <tx:attributes>
            <!-- 全部以開頭的方法都是read-only的,出現異常時回滾數據庫 -->
            <tx:method="get*" read-only="true" rollback-for="java.lang.Exception"/>
            <!-- 其餘方法使用默認的事務設置 -->
            <tx:method="*" />
        </tx:attributes>
    </tx:advice>
    
    <!-- AOP配置的元素 -->
    <aop:config>
        <!-- 切點,匹配com.abc.dao.impl包下的全部以impl結尾的類裏的全部方法的執行 -->
        <aop:pointcut id="myPointcut" expression="(* com.abc.dao.impl.*Impl.*(..))" />
        <!-- 指定在txAdvice切點,使用txAdvice事務加強處理 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut" />
    </aop:config>
</beans>

    上面的配置文件中,XMLSchema中啓用了Spring配置文件的tx、aop兩個命名空間,後面配置了一個事務加強處理,配置<tx:advice../>元素時只須要指定一個transaction-manager屬性,該屬性的默認值是"transactionManager"【提示:若是事務管理器Bean(PlatformTransactionManager的實現類)的名字是transactionManager,則配置<tx:advice../>元素時能夠省略指定transaction-manager屬性。只有當咱們爲事務管理器Bean指定了其餘名字時,才須要爲<tx:advice../>元素指定transaction-manager屬性】。
數據庫

    配置文件最後一段是<aop:config../>的定義,它確保由txAdvice切面定義事務加強功能能在合適的點被織入。首先咱們定義一個切點,命名爲myPointcut,而後用一個Advisor把這個切入點與txAdvice綁定在一塊兒,表示當myPointcut執行時,txAdvice定義的加強處理將被織入。
express

    <aop:advisor../>元素是一個很奇怪的東西,它用於配置一個Advisor,但標準的 AOP 概念裏並無所謂的"Advisor",Advisor是Spring 1.X遺留下來的一個東西,Advisor的做用很是簡單:將加強處理方法(Advice)和切入點(Pointcut)綁定在一塊兒,保證Advice所包含的加強處理將在對應的切點方法執行時被織入。
安全

    當咱們使用這種配置策略時,無需爲每一個業務Bean專門配置事務代理,Spring AOP會爲業務組件自動生成代理,程序能夠直接請求容器中的newsDao Bean,該Bean的方法已經具備了事務性——由於該Bean的實現類位於com.abc.dao.impl包下,並且類名以Impl結尾,和myPointcut切點的表達式匹配,故在指定裏面的方法時,事務將被自動織入。下面是主程序:spa

public class SpringTest {
    public static void main(String[] arg) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        NewsDao dao = (NewsDao)context.getBean("newsDao",NewsDao.class);
        dao.insert("新聞標題","新聞內容");
    }
}

    上面的程序中直接獲取Spring中的NewsDao,並調用其insert方法,由於Spring AOP會爲該Bean自動織入事務加強處理方式,因此newsDao Bean裏的全部方法都具備事務性。
.net

    採用這種方式來配置事務還有一個額外的優點:Spring容器中只有一個newsDao,該newsDao已經具備了事務性,不像採用TransactionProxyFactoryBean策略時,容器中有一個目標Bean,還有爲該目標Bean配置的事務代理Bean——當程序"不當心"獲取了目標Bean後,若是調用目標Bean,那麼此時Bean的方法時不具有事務性的,這可能埋下安全隱患。
代理

    採用<tx:advisor../>元素將Advice和切點綁定時,其實是由Spring提供的Bean後處理器完成的。Spring提供了BeanNameAutoProxyCreator、DefaultAdvisorAutoProxyCreator兩個Bean後處理器,它們均可之後處理容器中的Bean(爲它們織入切面中包含的加強處理)。前面咱們配置<aop:advisor../>元素時傳入一個txAdvice事務加強處理,因此Bean後處理器將全部Bean實例裏匹配切入點的方法織入事務操做的加強處理。

    配置<tx:advice../>元素時除了須要指定一個transaction-manager屬性之外,重要的是須要配置一個<attributes../>子元素,該子元素又能夠包含多個<method../>元素。其實,配置<tx:advice../>元素的重點就是配置<method../>元素,每一個<method../>子元素爲一批方法指定所需的事務語義,包括事務傳播屬性、事務隔離屬性、事務超時屬性、只讀事務、對指定異常回滾、對指定異常不回滾等。下面介紹<method../>元素能夠指定的幾個屬性:

  • name:必選屬性,與該事物語義關聯的方法名。支持使用通配符,例如"get*","handle*","save*","on*Event"等

  • propagation:指定事務的傳播行爲,該屬性值能夠是Propagation枚舉類的值的任意一種,各枚舉值看這裏

  • isolation:指定事務的隔離級別,該屬性值能夠是Isolation枚舉類的值的任意一種,各枚舉值的具體含義請參考API文檔。該屬性的默認值爲Isolation.DEFAULT

  • timeout:指定事務超時時間(單位:秒)指定-1表示不會超時。該屬性的默認值爲-1

  • read-only:指定事務是否只讀。該屬性默認值爲false

  • rollback-for:指定觸發事務回滾的異常類(使用全限定名),該屬性能夠指定多個異常類,多個異常類用英文逗號隔開

  • no-rollback-for:指定不觸發事務回滾的異常類(使用全限定名),該屬性能夠指定多個異常類,多個異常類用英文逗號隔開

    若是咱們想讓事務在遇到特定的Checked異常時自動回滾,則可藉助於rollback-for屬性,例如:

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- 全部以開頭的方法都是read-only的,出現異常時回滾數據庫 -->
        <tx:method="get*" read-only="true" rollback-for="java.lang.Exception"/>
    </tx:attributes>
</tx:advice>

    若是咱們想讓事務在出現某些特定的異常時不回滾,可以使用no-rollback-for屬性,例如:

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- 出現某些特定的Exception,不回滾 -->
        <tx:method="get*" read-only="true" 
            no-rollback-for="com.abc.exception.XxxException"/>
    </tx:attributes>
</tx:advice>


基於@Transactional註解

 Spring除了支持XMLSchema方式配置事務之外,還支持使用@Transactional註解來配置事務。該註解既能夠修飾Bean類,也能夠修飾Bean方法。修飾類時,代表這些事務設置對整個Bean都起做用;修飾方法時,代表事務設置只對該方法有效。

    和使用配置文件相似,使用@Transactional註解時,須要指定如下屬性:

  • isolation:事務隔離級別。默認爲底層事務的隔離級別

  • noRollbackFor:遇到指定異常時強制不回滾事務

  • noRollbackForClassName:遇到指定多個異常時強制不回滾事務,該屬性值能夠指定多個異常類名

  • propagation:事務傳播屬性

  • readOnly:事務是否只讀

  • rollbackFor:遇到指定異常時強制回滾事務

  • rollbackForClassName:遇到指定異常時強制回滾事務,該屬性值能夠指定多個異常類名

  • timeout:事務的超時時長

    下面使用@Transactional修飾須要添加事務的方法:

public class NewsDaoImpl implements NewsDao {
    @Transactional(propagation=Propagation.REQUIRED)
    public void insert(String title, String content) {
        //...
    }
}

    上面的Bean類中insert方法使用了@Transactional修飾,代表該方法就會具備事務性。僅使用這個註解配置還不夠,還須要在讓Spring根據註解來配置事務。因此還須要在Spring的配置文件中增長以下配置片斷:

 <!-- 配置JDBC數據源的局部事務管理器,使用DataSourceTransactionManager類,該類實現了    
      PlatformTransactionManager接口,是針對採用數據源鏈接的特定實現 -->    
<bean id="transactionManager"     
     class="org.springframework.jdbc.datasource.DataSourceTransactionManager">    
    <!-- 配置TransactionManager時須要注入數據源引用 -->    
    <property name="dataSource" ref="dataSource" />    
</bean>    

<tx:annotation-driven transaction-manager="transactionManager" />
相關文章
相關標籤/搜索