Spring 中經常使用的兩種事務配置方式以及事務的傳播性、隔離級別

1、註解式事務java

一、註解式事務在平時的開發中使用的挺多,工做的兩個公司中看到不少項目使用了這種方式,下面看看具體的配置demo。web

二、事務配置實例spring

(1)、spring+mybatis 事務配置數據庫

<!-- 定義事務管理器 -->  
<bean id="transactionManager"  
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
    <property name="dataSource" ref="dataSource" />  
</bean>  
<!--使用註釋事務 -->  
<tx:annotation-driven  transaction-manager="transactionManager" />

(2)、spring+hibernate 事務配置express

<!-- 事務管理器配置,單數據源事務 -->  
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">  
    <property name="sessionFactory" ref="sessionFactory" />  
</bean>  
  
<!-- 使用annotation定義事務 -->  
<tx:annotation-driven  transaction-manager="transactionManager"   proxy-target-class="true" />

看到上面的這兩段配置文件是否是很熟悉,對的這就是咱們平時看到的事務的配置,在spring的配置中配置數據源即dataSource、事務管理器,事務管理器使用不一樣的orm框架事務管理器類就不一樣,好比這裏使用的是mybatis 因此是數組

org.springframework.jdbc.datasource.DataSourceTransactionManager

若是使用hibernate 則事務管理器類爲安全

org.springframework.orm.hibernate3.HibernateTransactionManager

這是使用註解方式時要配置的,代碼中的具體的註解以及事務的傳播性、隔離級別通常在service 層中配置下面看看session

三、@Transactionalmybatis

(1)、這裏說明一下,有的把這個註解放在類名稱上面了,這樣你配置的這個@Transactional 對這個類中的全部public方法都起做用框架

(2)、@Transactional 方法方法名上,只對這個方法有做用,一樣必須是public的方法

好比這裏就對這個方法定義了一個事務同時設置了不少屬性:

@Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class,timeout=1,isolation=Isolation.DEFAULT)  
public void saveUser(Map<String, String> map) throws Exception {  
        System.out.println("方法開始");  
    for (int i = 0; i < 500000; i++) {  
            System.out.println("*");  
        }  
     System.out.println("進入保存");  
     userDao.saveUser(map);  
     System.out.println("退出保存");  
}

四、事物配置中有哪些屬性能夠配置

(1)、事務的傳播性:@Transactional(propagation=Propagation.REQUIRED) 

      若是有事務, 那麼加入事務, 沒有的話新建一個(默認狀況下)

(2)、事務的超時性:@Transactional(timeout=30) //默認是30秒 

      注意這裏說的是事務的超時性而不是Connection的超時性,這兩個是有區別的

(3)、事務的隔離級別:@Transactional(isolation = Isolation.READ_UNCOMMITTED)

      讀取未提交數據(會出現髒讀, 不可重複讀) 基本不使用

(4)、回滾:

 

指定單一異常類:@Transactional(rollbackFor=RuntimeException.class)

指定多個異常類:@Transactional(rollbackFor={RuntimeException.class, Exception.class})

該屬性用於設置須要進行回滾的異常類數組,當方法中拋出指定異常數組中的異常時,則進行事務回滾。

(5)、只讀:@Transactional(readOnly=true)

該屬性用於設置當前事務是否爲只讀事務,設置爲true表示只讀,false則表示可讀寫,默認值爲false。

ok 這種註解方式實現事務的配置以及一些屬性的定義,其實事務的東西還有不少要注意的事項,若是要深刻學習的話要學習的東西還不少,這裏只是簡單記錄一下

那咱們要注意什麼那:

一、在spring配置文件中引入<tx:>命名空間:xmlns:tx="http://www.springframework.org/schema/tx"

                                 http://www.springframework.org/schema/tx 
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd

<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
     xmlns:tx="http://www.springframework.org/schema/tx"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:aop="http://www.springframework.org/schema/aop"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
                  http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
                  http://www.springframework.org/schema/context  
                  http://www.springframework.org/schema/context/spring-context-3.2.xsd  
                  http://www.springframework.org/schema/aop   
                  http://www.springframework.org/schema/aop/spring-aop.xsd        
                 http://www.springframework.org/schema/tx   
                 http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

二、@Transactional 只能被應用到public方法上, 對於其它非public的方法,若是標記了@Transactional也不會報錯,但方法沒有事務功能.

三、用 spring 事務管理器,由spring來負責數據庫的打開,提交,回滾.默認遇到運行期例外(throw new RuntimeException("註釋");)會回滾,即遇到不受檢查(unchecked)的例外時回滾;而遇到須要捕獲的例外(throw new Exception("註釋");)不會回滾,即遇到受檢查的例外(就是非運行時拋出的異常,編譯器會檢查到的異常叫受檢查例外或說受檢查異常)時,需咱們指定方式來讓事務回滾 要想全部異常都回滾,要加上 @Transactional( rollbackFor={Exception.class,其它異常}) .若是讓unchecked例外不回滾: @Transactional(notRollbackFor=RunTimeException.class)
以下:
@Transactional(rollbackFor=Exception.class) //指定回滾,遇到異常Exception時回滾
public void methodName() {
throw new Exception("註釋");

}
@Transactional(noRollbackFor=Exception.class)//指定不回滾,遇到運行期例外(throw new RuntimeException("註釋");)會回滾
public ItimDaoImpl getItemDaoImpl() {
throw new RuntimeException("註釋");
}

四、@Transactional 註解應該只被應用到 public 可見度的方法上。 若是你在 protected、private 或者 package-visible 的方法上使用 @Transactional 註解,它也不會報錯, 可是這個被註解的方法將不會展現已配置的事務設置。


五、@Transactional 註解能夠被應用於接口定義和接口方法、類定義和類的 public 方法上。然而,請注意僅僅 @Transactional 註解的出現不足於開啓事務行爲,它僅僅 是一種元數據,可以被能夠識別 @Transactional 註解和上述的配置適當的具備事務行爲的beans所使用。上面的例子中,其實正是 <tx:annotation-driven/>元素的出現 開啓 了事務行爲。


六、Spring團隊的建議是你在具體的類(或類的方法)上使用 @Transactional 註解,而不要使用在類所要實現的任何接口上。你固然能夠在接口上使用 @Transactional 註解,可是這將只能當你設置了基於接口的代理時它才生效。由於註解是 不能繼承 的,這就意味着若是你正在使用基於類的代理時,那麼事務的設置將不能被基於類的代理所識別,並且對象也將不會被事務代理所包裝(將被確認爲嚴重的)。因 此,請接受Spring團隊的建議而且在具體的類上使用 @Transactional 註解。

2、使用AOP的方式實現事務的配置

一、這種事務使用也不少,下面咱們來看看簡單的例子

二、事務配置實例:

(1)、配置文件

<!-- 定義事務管理器 -->  
    <bean id="transactionManager"  
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
        <property name="dataSource" ref="dataSource" />  
    </bean>  
    <!-- 下面使用aop切面的方式來實現 -->  
    <tx:advice id="TestAdvice" transaction-manager="transactionManager">  
        <!--配置事務傳播性,隔離級別以及超時回滾等問題 -->  
        <tx:attributes>  
            <tx:method name="save*" propagation="REQUIRED" />  
            <tx:method name="del*" propagation="REQUIRED" />  
            <tx:method name="update*" propagation="REQUIRED" />  
            <tx:method name="add*" propagation="REQUIRED" />  
            <tx:method name="*" rollback-for="Exception" />  
        </tx:attributes>  
    </tx:advice>  
    <aop:config>  
        <!--配置事務切點 -->  
        <aop:pointcut id="services"  
            expression="execution(* com.website.service.*.*(..))" />  
        <aop:advisor pointcut-ref="services" advice-ref="TestAdvice" />  
    </aop:config>

上面咱們看到了,簡單的配置了事務,其中tx:attributes中設置了事務的傳播性,隔離級別以及那種問題能進行回滾超時等這些問題,也就是你本身按照業務需求定製一個事務來知足你的業務需求。

注意: 這裏注意一下,在tx:method中配置了rollback_for 中配置的Exception 這個是運行時的異常纔會回滾否則其餘異常是不會回滾的!

@Service("userService")  
public class UserService {  
    @Autowired  
    private UserDao userDao;  
    public void saveUser(Map<String, String> map) throws Exception {  
         userDao.saveUser(map);  
         throw new RuntimeException();  
         // throw new Exception ();  
           
    }  
}

這裏咱們看到了,若是拋出的是一個運行時異常則會回滾而若是拋出的不是運行時異常則會不回滾的。

須要注意的地方:

(1)、在spring 配置文件中引入:xmlns:aop="http://www.springframework.org/schema/aop"

 http://www.springframework.org/schema/aop 
                  http://www.springframework.org/schema/aop/spring-aop.xsd

<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
     xmlns:tx="http://www.springframework.org/schema/tx"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:aop="http://www.springframework.org/schema/aop"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans   
                  http://www.springframework.org/schema/beans/spring-beans-3.2.xsd  
                  http://www.springframework.org/schema/context  
                  http://www.springframework.org/schema/context/spring-context-3.2.xsd  
                  http://www.springframework.org/schema/aop   
                  http://www.springframework.org/schema/aop/spring-aop.xsd        
                 http://www.springframework.org/schema/tx   
                 http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">

(2) advice(建議)的命名:因爲每一個模塊都會有本身的Advice,因此在命名上須要做出規範,初步的構想就是模塊名+Advice(只是一種命名規範)。

(3) tx:attribute標籤所配置的是做爲事務的方法的命名類型。

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

        其中*爲通配符,即表明以save爲開頭的全部方法,即表示符合此命名規則的方法做爲一個事務。

        propagation="REQUIRED"表明支持當前事務,若是當前沒有事務,就新建一個事務。這是最多見的選擇。

(4) aop:pointcut標籤配置參與事務的類,因爲是在Service中進行數據庫業務操做,配的應該是包含那些做爲事務的方法的Service類。

       首先應該特別注意的是id的命名,一樣因爲每一個模塊都有本身事務切面,因此我以爲初步的命名規則由於 all+模塊名+ServiceMethod。並且每一個模塊之間不一樣之處還在於如下一句:

       expression="execution(* com.test.testAda.test.model.service.*.*(..))"

       其中第一個*表明返回值,第二*表明service下子包,第三個*表明方法名,「(..)」表明方法參數。

(5) aop:advisor標籤就是把上面咱們所配置的事務管理兩部分屬性整合起來做爲整個事務管理。

(6)注意標紅的地方

ok 到這裏兩種配置方式簡單的demo 都有了,下面咱們來看看tx:method 中還有那些屬性能夠配置

下面來看看aop 這種方式來配置的時候咱們還能配置那些屬性:

<tx:advice id="advice" transaction-manager="txManager">
  <tx:attributes>
    <!-- tx:method的屬性:
          * name 是必須的,表示與事務屬性關聯的方法名(業務方法名),對切入點進行細化。通配符(*)能夠用來指定一批關聯到相同的事務屬性的方法。
                              如:'get*'、'handle*'、'on*Event'等等.
          * propagation  不是必須的 ,默認值是REQUIRED 
                            表示事務傳播行爲, 包括REQUIRED,SUPPORTS,MANDATORY,REQUIRES_NEW,NOT_SUPPORTED,NEVER,NESTED
                                     * isolation    不是必須的 默認值DEFAULT 
                            表示事務隔離級別(數據庫的隔離級別) 
          * timeout      不是必須的 默認值-1(永不超時)
                            表示事務超時的時間(以秒爲單位) 
          
          * read-only    不是必須的 默認值false不是隻讀的 
                            表示事務是否只讀? 
          
          * rollback-for 不是必須的   
                            表示將被觸發進行回滾的 Exception(s);以逗號分開。
                            如:'com.foo.MyBusinessException,ServletException' 
          
          * no-rollback-for 不是必須的  
                              表示不被觸發進行回滾的 Exception(s);以逗號分開。
                              如:'com.foo.MyBusinessException,ServletException'
                              
                              
        任何 RuntimeException 將觸發事務回滾,可是任何 checked Exception 將不觸發事務回滾    
        -->
     <tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
     <tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
     <tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
     <!-- 其餘的方法之只讀的 -->
     <tx:method name="*" read-only="true"/>
  </tx:attributes>
</tx:advice>

OK 兩種配置方式咱們也都簡單學習了,兩種配置方式有哪些屬性要配置咱們也瞭解了,可是,這裏只是說了有這兩種經常使用的方法,而沒有具體說事務以及事務的配置帶來的數據的安全性以及性能的影響,其實事務不是那麼簡單,具體深刻學習但願之後有總結!

下面給你們列出spring事務的幾種傳播特性:

1. PROPAGATION_REQUIRED: 若是存在一個事務,則支持當前事務。若是沒有事務則開啓  
2. PROPAGATION_SUPPORTS: 若是存在一個事務,支持當前事務。若是沒有事務,則非事務的執行  
3. PROPAGATION_MANDATORY: 若是已經存在一個事務,支持當前事務。若是沒有一個活動的事務,則拋出異常。  
4. PROPAGATION_REQUIRES_NEW: 老是開啓一個新的事務。若是一個事務已經存在,則將這個存在的事務掛起。  
5. PROPAGATION_NOT_SUPPORTED: 老是非事務地執行,並掛起任何存在的事務。  
6. PROPAGATION_NEVER: 老是非事務地執行,若是存在一個活動事務,則拋出異常  
7. PROPAGATION_NESTED:若是一個活動的事務存在,則運行在一個嵌套的事務中. 若是沒有活動事務,   
      則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執行

Spring事務的隔離級別

1. ISOLATION_DEFAULT: 這是一個PlatfromTransactionManager默認的隔離級別,使用數據庫默認的事務隔離級別,另外四個與JDBC的隔離級別相對應  
2. ISOLATION_READ_UNCOMMITTED: 這是事務最低的隔離級別,它充許令外一個事務能夠看到這個事務未提交的數據,這種隔離級別會產生髒讀,不可重複讀和幻像讀。  
3. ISOLATION_READ_COMMITTED: 保證一個事務修改的數據提交後才能被另一個事務讀取。另一個事務不能讀取該事務未提交的數據  
4. ISOLATION_REPEATABLE_READ: 這種事務隔離級別能夠防止髒讀,不可重複讀。可是可能出現幻像讀,它除了保證一個事務不能讀取另外一個事務未提交的數據外,還保證了避免下面的狀況產生(不可重複讀)。  
5. ISOLATION_SERIALIZABLE 這是花費最高代價可是最可靠的事務隔離級別。事務被處理爲順序執行,除了防止髒讀,不可重複讀外,還避免了幻像讀。

事務的隔離級別和數據庫中是同樣的你們能夠看數據庫事務隔離級別就能明白了可是事務的傳播性是個什麼鬼貌似以前沒聽過那下面就來看看

咱們都知道事務的概念,那麼事務的傳播特性是什麼呢?(此處着重介紹傳播特性的概念,關於傳播特性的相關配置就不介紹了,能夠查看spring的官方文檔)在咱們用SSH開發項目的時候,咱們通常都是將事務設置在Service層 那麼當咱們調用Service層的一個方法的時候它可以保證咱們的這個方法中執行的全部的對數據庫的更新操做保持在一個事務中,在事務層裏面調用的這些方法要麼所有成功,要麼所有失敗。那麼事務的傳播特性也是從這裏提及的。若是你在你的Service層的這個方法中,除了調用了Dao層的方法以外,還調用了本類的其餘的Service方法,那麼在調用其餘的Service方法的時候,這個事務是怎麼規定的呢,我必須保證我在我方法裏掉用的這個方法與我自己的方法處在同一個事務中,不然若是保證事物的一致性。事務的傳播特性就是解決這個問題的,「事務是會傳播的」在Spring中有針對傳播特性的多種配置咱們大多數狀況下只用其中的一種:PROPGATION_REQUIRED:這個配置項的意思是說當我調用service層的方法的時候開啓一個事務(具體調用那一層的方法開始建立事務,要看你的aop的配置),那麼在調用這個service層裏面的其餘的方法的時候,若是當前方法產生了事務就用當前方法產生的事務,不然就建立一個新的事務。這個工做使由Spring來幫助咱們完成的。之前沒有Spring幫助咱們完成事務的時候咱們必須本身手動的控制事務,例如當咱們項目中僅僅使用hibernate,而沒有集成進spring的時候,咱們在一個service層中調用其餘的業務邏輯方法,爲了保證事物必須也要把當前的hibernate session傳遞到下一個方法中,或者採用ThreadLocal的方法,將session傳遞給下一個方法,其實都是一個目的。如今這個工做由spring來幫助咱們完成,就可讓咱們更加的專一於咱們的業務邏輯。而不用去關心事務的問題。默認狀況下當發生RuntimeException的狀況下,事務纔會回滾,因此要注意一下 若是你在程序發生錯誤的狀況下,有本身的異常處理機制定義本身的Exception,必須從RuntimeException類繼承 這樣事務纔會回滾!

相關文章
相關標籤/搜索