Spring事務看這個肯定會

Spring的AOP配置

    1.第一種:註解配置AOP

    2.第二種:xml配置AOP

 

使用Spring AOP實現聲明式事務管理

1.基於XML配置,現在也有很多通過註解的方式來配置事務管理類

(1)配置事務管理類

 

[html] view plain copy

  1.  <!-- 定義事務管理器 -->    
  2. <bean id="transactionManager"    
  3.     class="org.springframework.jdbc.datasource.DataSourceTransactionManager">    
  4.     <property name="dataSource" ref="dataSource" />    
  5. </bean>    

在spring的配置中配置數據源(dataSource)、事務管理器,事務管理器使用不同的orm框架事務管理器類就不同,mybatis 是org.springframework.jdbc.datasource.DataSourceTransactionManager  。而hibernate事務管理器爲org.springframework.orm.hibernate3.HibernateTransactionManager  

   或者通過註解配置事務管理類

   @Bean

    public LocalContainerEntityManagerFactoryBean entityManagerFactory(){

    }

    @Bean
   public PlatformTransactionManager transactionManager() {
    LocalContainerEntityManagerFactoryBean factoryBean = entityManagerFactory();
        if (factoryBean != null) {
        return new JpaTransactionManager(factoryBean.getObject());
        }
    return null;
   }   

(2)配置事務屬性

[html] view plain copy

  1. <!-- 配置事務的屬性 -->    
  2.     <tx:advice id="TestAdvice" transaction-manager="transactionManager">    
  3.         <!--配置事務傳播性,隔離級別以及超時回滾等問題 -->    
  4.         <tx:attributes>    
  5.             <tx:method name="search*" propagation="REQUIRED" read-only="true" isolation="DEFAUT" TIMEOUT="-1" />    
  6.             <tx:method name="del*" propagation="REQUIRED" />    
  7.             <tx:method name="update*" propagation="REQUIRED" />    
  8.             <tx:method name="add*" propagation="REQUIRED" />    
  9.         </tx:attributes>    
  10.     </tx:advice>  

事務屬性在<tx:method>中進行設置,Spring支持對不同的方法設置不同的事務屬性,所以可以爲一個<tx:advice>設置多個<tx:method>,其中name屬性指定匹配的方法(這裏需要對這些方法名進行約定,如果事務切入點在service上,則最好和Dao的方法命名區分開,也不要使用get set關鍵字,防止和屬性的getter setter發生混淆)

事務有以下幾個常用屬性:

a.read-only:設置該事務中是否允許修改數據。(對於只執行查詢功能的事務,設置爲TRUE可以提高事務的執行速度)  

b.propagation:事務的傳播機制。一般設置爲required。可以保證在事務中的代碼只在當前事務中運行,防止創建多個事務。

c.isolation:事務隔離級別。不是必須的。默認值是default。

d.timeout:允許事務運行的最長時間,以秒爲單位。

e.rollback-for:觸發回滾的異常。

f.no-rollback-for:不會觸發回滾的異常。

Table 9.1. <tx:method/> 有關的設置

 

屬性 是否需要? 默認值 描述
name  

與事務屬性關聯的方法名。通配符(*)可以用來指定一批關聯到相同的事務屬性的方法。 如:'get*'、'handle*'、'on*Event'等等。

propagation REQUIRED 事務傳播行爲
isolation DEFAULT 事務隔離級別
timeout -1 事務超時的時間(以秒爲單位)
read-only false 事務是否只讀?
rollback-for  

將被觸發進行回滾的 Exception(s);以逗號分開。 如:'com.foo.MyBusinessException,ServletException'

no-rollback-for  

 被觸發進行回滾的 Exception(s);以逗號分開。 如:'com.foo.MyBusinessException,ServletException'

***實際開發中,對於只執行查詢功能的事務,要設置read-only爲TRUE,其他屬性一般使用默認值即可。

(3)配置事務的AOP切入點

[html] view plain copy

  1. <aop:config>    
  2.         <!--配置事務切點 -->    
  3.         <aop:pointcut id="services"    
  4.             expression="execution(public* com.pb.service.*.*(..))" />    
  5.         <aop:advisor pointcut-ref="services" advice-ref="TestAdvice" />    
  6.     </aop:config>    

 

該設置的含義是:對於com.pb.service.impl包及子包下的所有類的所有公共方法進行切入。(被切入的 方法經過<tx:method>篩選)web應用程序最合適的事務切入點是Service的方法上。

----通過以上三個步驟設置好聲明式事務後,當Service中 的業務方法被調用之前,Spring會獲取事務對象並啓動事務。並使用try-catch-finally來處理異常。業務方法執行成功則會提交事務,默認情況下如果拋出了RuntimeException 或者Rrror 對象就會回滾事務。(注意: 這裏注意一下,在tx:method中配置了rollback_for 中配置的Exception 這個是運行時的異常纔會回滾不然其他異常是不會回滾的!)

2.使用annotation配置

*1.在事務管理的dao實現類之前標註@Transactional

*2.在要進行事務管理的方法前加上@Transactional(propagation= Propagation.REQUIRED)

*3.在配置文件中指定驅動:<tx:annotation-driven transaction-manager="transactionManager" />

 

[html] view plain copy

  1. package demo.spring.dao;  
  2.   
  3. import java.util.Iterator;  
  4. import java.util.List;  
  5.   
  6. import javax.sql.DataSource;  
  7.   
  8. import org.springframework.jdbc.core.JdbcTemplate;  
  9. import org.springframework.transaction.annotation.Propagation;  
  10. import org.springframework.transaction.annotation.Transactional;  
  11.   
  12. import demo.spring.entity.Person;  
  13. @Transactional//將此類進行事務管理  
  14. public class PersonDaoImpl implements PersonDao {  
  15.     private JdbcTemplate jt;  
  16.       
  17.     public void setDataSource(DataSource dataSource){  
  18.         jt = new JdbcTemplate(dataSource);  
  19.     }  
  20.     @Override  
  21.     public void insert(long id, String name, int age) {  
  22.         jt.update("insert into person values('"+id+"','"+name+"','"+age+"')");  
  23.   
  24.     }  
  25.   
  26.     @Transactional(propagation= Propagation.REQUIRED)//定義要事務管理的方法,指定傳播行爲  
  27.     public void batchInsert(List persons) {  
  28.         for(Iterator it = persons.iterator(); it.hasNext(); ){  
  29.             Person p = (Person) it.next();  
  30.             insert(p.getId(),p.getName(),p.getAge());  
  31.         }  
  32.     }  
  33.   
  34. }  
  35.  

以上內容轉載於:https://blog.csdn.net/c_w_d/article/details/63252340

 

思考:在配置文件中對com.pb.service.impl包及子包下的所有類的所有公共方法進行切入,但是在這個包下面的要進行事務管理的方法沒有加@Transactional(propagation= Propagation.REQUIRED),還能對該方法進行事務管理嗎?

Spring中常用事務的傳播機制(事務類型):

  • PROPAGATION_REQUIRED--支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。
  • 解釋如下:1、如果ServiceA.methodA已經起了事務,這時調用ServiceB.methodB,ServiceB.methodB看到自己已經運行在ServiceA.methodA的事務內部,就不再起新的事務。這時只有外部事務並且他們是共用的,所以這時ServiceA.methodA或者ServiceB.methodB無論哪個發生異常methodA和methodB作爲一個整體都將一起回滾。
      2、如果ServiceA.methodA沒有事務,ServiceB.methodB就會爲自己分配一個事務。這樣,在ServiceA.methodA中是沒有事務控制的。只是在ServiceB.methodB內的任何地方出現異常,ServiceB.methodB將會被回滾,不會有ServiceA.methodA的回滾
  • PROPAGATION_SUPPORTS--支持當前事務,如果當前沒有事務,就以非事務方式執行。
  • PROPAGATION_MANDATORY--支持當前事務,如果當前沒有事務,就拋出異常。
  • PROPAGATION_REQUIRES_NEW--新建事務,如果當前存在事務,把當前事務掛起。
  • 解釋如下:這個就比較繞口了。 比如我們設計ServiceA.methodA的事務級別爲PROPAGATION_REQUIRED,ServiceB.methodB的事務級別爲PROPAGATION_REQUIRES_NEW,那麼當執行到ServiceB.methodB的時候,ServiceA.methodA所在的事務就會掛起,ServiceB.methodB會起一個新的事務,等待ServiceB.methodB的事務完成以後,他才繼續執行。他與PROPAGATION_REQUIRED 的事務區別在於事務的回滾程度了。因爲ServiceB.methodB是新起一個事務,那麼就是存在兩個不同的事務。如果ServiceB.methodB已經提交,那麼ServiceA.methodA失敗回滾,ServiceB.methodB是不會回滾的。如果ServiceB.methodB失敗回滾,如果他拋出的異常被ServiceA.methodA捕獲,ServiceA.methodA事務仍然可能提交。
  • PROPAGATION_NOT_SUPPORTED--以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
  • 解釋如下:比如ServiceA.methodA的事務級別是PROPAGATION_REQUIRED ,而ServiceB.methodB的事務級別是PROPAGATION_NOT_SUPPORTED ,
    那麼當執行到ServiceB.methodB時,ServiceA.methodA的事務掛起,而他以非事務的狀態運行完,再繼續ServiceA.methodA的事務。
  • PROPAGATION_NEVER--以非事務方式執行,如果當前存在事務,則拋出異常。
  • 解釋如下:假設ServiceA.methodA的事務級別是PROPAGATION_REQUIRED, 而ServiceB.methodB的事務級別是PROPAGATION_NEVER ,
    那麼ServiceB.methodB就要拋出異常了。
  • PROPAGATION_REQUIRED類似的操作。
  • PROPAGATION_NESTED--如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則進行與PROPAGATION_REQUIRED類似的操作。

       解釋如下: 理解Nested的關鍵是savepoint。他與PROPAGATION_REQUIRES_NEW的區別是,PROPAGATION_REQUIRES_NEW另起一個事務,將會與    他的父事務相互獨立,而Nested的事務和他的父事務是相依的,他的提交是要等和他的父事務一塊提交的。也就是說,如果父事務最後回滾,    他也要回滾的。而Nested事務的好處是他有一個savepoint。

*****************************************
ServiceA {   
       
       
     void methodA() {   
         try {
      //savepoint   
             ServiceB.methodB();    //PROPAGATION_NESTED 級別
         } catch (SomeException) {   
             // 執行其他業務, 如 ServiceC.methodC();   
         }   
     }   
  
}   
********************************************
也就是說ServiceB.methodB失敗回滾,那麼ServiceA.methodA也會回滾到savepoint點上,ServiceA.methodA可以選擇另外一個分支,比如
ServiceC.methodC,繼續執行,來嘗試完成自己的事務。

 

Spring中常用事務的隔離級別:

  1. ISOLATION_DEFAULT:用底層數據庫的默認隔離級別,數據庫管理員設置什麼就是什麼
  2. ISOLATION_READ_UNCOMMITTED(未提交讀):最低隔離級別、事務未提交前,就可被其他事務讀取(會出現幻讀、髒讀、不可重複讀)
  3. ISOLATION_READ_COMMITTED(提交讀):一個事務提交後才能被其他事務讀取到(該隔離級別禁止其他事務讀取到未提交事務的數據、所以還是會造成幻讀、不可重複讀)、sql server默認級別
  4. ISOLATION_REPEATABLE_READ(可重複讀):可重複讀,保證多次讀取同一個數據時,其值都和事務開始時候的內容是一致,禁止讀取到別的事務未提交的數據(該隔離基本可防止髒讀,不可重複讀(重點在修改),但會出現幻讀(重點在增加與刪除))(MySql默認級別,更改可通過set transaction isolation level 級別)
  5. ISOLATION_SERIALIZABLE(序列化):代價最高最可靠的隔離級別(該隔離級別能防止髒讀、不可重複讀、幻讀)
    1. 丟失更新:兩個事務同時更新一行數據,最後一個事務的更新會覆蓋掉第一個事務的更新,從而導致第一個事務更新的數據丟失,這是由於沒有加鎖造成的;
    2. 幻讀:同樣的事務操作過程中,不同時間段多次(不同事務)讀取同一數據,讀取到的內容不一致(一般是行數變多或變少)。
    3. 髒讀:一個事務讀取到另外一個未提及事務的內容,即爲髒讀。
    4. 不可重複讀:同一事務中,多次讀取內容不一致(一般行數不變,而內容變了)。

幻讀與不可重複讀的區別:幻讀的重點在於插入與刪除,即第二次查詢會發現比第一次查詢數據變少或者變多了,以至於給人一種幻象一樣,而不可重複讀重點在於修改,即第二次查詢會發現查詢結果比第一次查詢結果不一致,即第一次結果已經不可重現了。

數據庫隔離級別越高,執行代價越高,併發執行能力越差,因此在實際項目開發使用時要綜合考慮,爲了考慮併發性能一般使用提交讀隔離級別,它能避免丟失更新和髒讀,儘管不可重複讀和幻讀不能避免,但可以在可能出現的場合使用悲觀鎖或樂觀鎖來解決這些問題。

悲觀鎖與樂觀鎖可參考:http://blog.csdn.net/liaohaojian/article/details/62416972

 

 

第三部分

關於AOP切入點pointcut中的expression的理解

  1.  <aop:pointcut id="services"    
  2.             expression="execution(public* com.pb.service.*.*(..))" />  
  3.  

 

execution(* com.spring.aop.*.*(..))

這是 com.spring.aop包下所有的類的所有方法。。

第一個*代表所有的返回值類型

第二個*代表所有的類

第三個*代表類所有方法

最後一個..代表所有的參數。

 

網上其它示例1:
<aop:pointcut id="serviceMethod" expression="execution(* *.*Service.*(..))" />

第一個* 表示任意返回值類型
第二個* 表示以任意名字開頭的package. 如 com.xx.
第三個* 表示 通配 *service下的任意類

第四個* 表示 以任意名字開頭的方法名 

最後二個.. 表示通配 方法可以有0個或多個參數

 

部分轉載於:https://blog.csdn.net/qq525099302/article/details/53996344,

https://blog.csdn.net/wwh578867817/article/details/51736723

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章