Spring中事務的配置與使用


1.  spring的事務如何配置

    spring的聲明式事務配置:

    1. <!-- 配置sessionFactory -->

         <bean id="sessionFactory"

                   class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

                   <property name="configLocation">

                            <value>/WEB-INF/classes/hibernate.cfg.xml</value>

                   </property>

         </bean> 

    2. 配置事務管理器

       <!-- 配置事務管理器 -->

         <bean id="transactionManager"

                   class="org.springframework.orm.hibernate3.HibernateTransactionManager">

                   <property name="sessionFactory">

                            <ref local="sessionFactory" />

                   </property>

         </bean>

    3. 配置事務特性

       <tx:advice id="txAdvice"  transaction-manager="transactionManager">

                   <tx:attributes>

                             <tx:method name="add*" propagation="REQUIRED"/>

                    <tx:method name="update*" propagation="REQUIRED"/>

                    <tx:method name="del*" propagation="REQUIRED"/>

                    <tx:method name="*" read-only="true"/>

                </tx:attributes>

       </tx:advice>

    4. 配置哪些類的哪些方法配置事務

       <aop:config>

           <aop:pointcut id="allManagerMethod" ession="execution(* com.yyaccp.service.impl.*.*(..))"/>

           <aop:advisor advice-ref="txAdvice" pointcut-ref="allManagerMethod">

       </aop:config>

Spring整合Ibatis事務管理管理配置參考:

http://www.cnblogs.com/standcloud/articles/2602099.html

http://www.cnblogs.com/Angi/articles/2007563.html

要設置dataSource 的自動提交為false,讓spring 去管理提交,自動提交默認是true

advisor 是spring aop中的一個概念。
advisor 可以翻譯為增強器, 他是切入點(pointcut)和advice 的適配器。 它有兩部門組成:一個增強以及一個說明在何處增強的切入點。增強器完整的模塊化了一個方面(因為一個方面,就是由在什么地方增強和怎么增強組成的) 。 增強和切入點可以復用。

Spring Transaction中有一個很重要的屬性:Propagation。主要用來配置當前需要執行的方法,與當前是否有transaction之間的關系。

我曉得有點兒抽象,這也是為什么我想要寫這篇博客的原因。看了后面的例子,大家應該就明白了。

 

一、Propagation取值:

REQUIRED(默認值):在有transaction狀態下執行;如當前沒有transaction,則創建新的transaction;

SUPPORTS:如當前有transaction,則在transaction狀態下執行;如果當前沒有transaction,在無transaction狀態下執行;

MANDATORY:必須在有transaction狀態下執行,如果當前沒有transaction,則拋出異常IllegalTransactionStateException;

REQUIRES_NEW:創建新的transaction並執行;如果當前已有transaction,則將當前transaction掛起;

NOT_SUPPORTED:在無transaction狀態下執行;如果當前已有transaction,則將當前transaction掛起;

NEVER:在無transaction狀態下執行;如果當前已有transaction,則拋出異常IllegalTransactionStateException。

 

二、REQUIRED與REQUIRED_NEW

上面描述的6種propagation屬性配置中,最難以理解,並且容易在transaction設計時出現問題的是REQUIRED和REQURED_NEW這兩者的區別。當程序在某些情況下拋出異常時,如果對於這兩者不夠了解,就可能很難發現而且解決問題。

 

下面我們給出三個場景進行分析:

場景一:

ServiceA.java:

public class ServiceA {
    @Transactional
    public void callB() {
        serviceB.doSomething();
    }
}

ServiceB.java

public class ServiceB {
    @Transactional
    public void doSomething() {
        throw new RuntimeException("B throw exception");
    }
}

這種情況下,我們只需要在調用ServiceA.callB時捕獲ServiceB中拋出的運行時異常,則transaction就會正常的rollback。

 

場景二

在保持場景一中ServiceB不變,在ServiceA中調用ServiceB的doSomething時去捕獲這個異常,如下:

public class ServiceA {
    @Transactional
    public void callB() {
        try {
            serviceB.doSomething();
        } catch (RuntimeException e) {
            System.err.println(e.getMessage());
        }
    }
}

這個時候,我們再調用ServiceA的callB。程序會拋出org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only這樣一個異常信息。原因是什么呢?

因為在ServiceA和ServiceB中的@Transactional propagation都采用的默認值:REQUREID。根據我們前面講過的REQUIRED特性,當ServiceA調用ServiceB的時候,他們是處於同一個transaction中。如下圖所示:

當ServiceB中拋出了一個異常以后,ServiceB會把當前的transaction標記為需要rollback。但是ServiceA中捕獲了這個異常,並進行了處理,認為當前transaction應該正常commit。此時就出現了前后不一致,也就是因為這樣,拋出了前面的UnexpectedRollbackException。

 

 

場景三

在保持場景二中ServiceA不變,修改ServiceB中方法的propagation配置為REQUIRES_NEW,如下:

public class ServiceB {
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void doSomething() {
        throw new RuntimeException("B throw exception");
    }
}

此時,程序可以正常的退出了,也沒有拋出UnexpectedRollbackException。原因是因為當ServiceA調用ServiceB時,serviceB的doSomething是在一個新的transaction中執行的。如下圖所示:

所以,當doSomething拋出異常以后,僅僅是把新創建的transaction rollback了,而不會影響到ServiceA的transaction。ServiceA就可以正常的進行commit。

當然這里把ServiceA和ServiceB放在兩個獨立的transaction是否成立,還需要再多多考慮你的業務需求。

 

Transaction不是一個新東西了,那對於transaction的使用會不會有一些模式?一些經驗之談呢?答案肯定是有的,以后博客再說。

 Pointcut 是指那些方法需要被執行"AOP",是由"Pointcut Expression"來描述的

任意公共方法的執行:

execution(* com.aptech.jb.epet.dao.hibimpl.*.*(..))
這樣寫應該就可以了
這是com.aptech.jb.epet.dao.hibimpl 包下所有的類的所有方法。。
第一個*代表所有的返回值類型
第二個*代表所有的類
第三個*代表類所有方法
最后一個..代表所有的參數。


execution(public * *(..))
任何一個以“set”開始的方法的執行:
execution(* set*(..))
AccountService 接口的任意方法的執行:
execution(* com.xyz.service.AccountService.*(..))
定義在service包里的任意方法的執行:
execution(* com.xyz.service.*.*(..))
定義在service包和所有子包里的任意類的任意方法的執行:
execution(* com.xyz.service..*.*(..))

帶有@Transactional標注的所有類的任意方法.
@within(org.springframework.transaction.annotation.Transactional)
@target(org.springframework.transaction.annotation.Transactional)
帶有@Transactional標注的任意方法.
@annotation(org.springframework.transaction.annotation.Transactional)
***> @within和@target針對類的注解,@annotation是針對方法的注解

參數帶有@Transactional標注的方法.
@args(org.springframework.transaction.annotation.Transactional)
參數為String類型(運行是決定)的方法.
args(String)

參考文獻:

http://blog.csdn.net/kkdelta/article/details/7441829

http://blog.csdn.net/it_man/article/details/5074371

http://blog.csdn.net/happyangelling/article/details/6228208


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM