1. 程式人生 > >spring+mybatis兩種事務控制編寫

spring+mybatis兩種事務控制編寫

一.宣告式事務管理
1.spring主配置檔案頭部新增以下程式碼
xmlns:aop=“http://www.springframework.org/schema/aop
xmlns:tx=“http://www.springframework.org/schema/tx
xsi:schemaLocation下新增如下程式碼:
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.1.xsd


2.配置事務管理器

<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">       
          <property name="dataSource" ref="dataSource"></property>  
</bean>

3.配置需要加入事務的規則

 <tx:advice id="iccardTxAdvice" transaction-manager="transactionManager">  
        <tx:attributes>  
          <tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" no-rollback-for="java.lang.RuntimeException"/>  
          <tx:method name="insert*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.RuntimeException" />  
          <tx:method name="add*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.RuntimeException" />  
          <tx:method name="create*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.RuntimeException" />  
          <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception" />  
            
          <tx:method name="find*" propagation="SUPPORTS" />  
          <tx:method name="get*" propagation="SUPPORTS" />  
          <tx:method name="select*" propagation="SUPPORTS" />  
          <tx:method name="query*" propagation="SUPPORTS" />  
        </tx:attributes>  
    </tx:advice>  
      
    <!-- 把事務控制在service層 -->  
    <aop:config>      
        <aop:pointcut id="iccardTerm" expression="execution(public * com.ucmed.hunst.service.*.*(..))" />  
        <aop:advisor pointcut-ref="iccardTerm" advice-ref="iccardTxAdvice" />  
    </aop:config> 

二.註解式事務管理
1.

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

2.在需要加入事務的方法或者類上新增@Transactional

事物配置中有哪些屬性可以配置

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

例如:

@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)、REQUIRED

如果當前方法已經在事務中,那麼就以父事務執行,不需要新建事務;如果當前方法不在事務中,那麼就為當前方法新建事務。回滾情況:父子方法中任何地方出現問題,都會全部回滾。

2)、SURPPORTED

如果當前方法已經在事務中,那麼就以當前事務執行;如果當前方法不再事務中,那麼就以非事務方式執行。如果執行在事務中,那麼只要出現異常都會回滾。

3)、NOT_SURPPORTED

如果當前方法已經在事務中,那麼就掛起當前事務,以非事務方式執行,方法執行完畢後,恢復事務;如果當前方法不再事務中,那麼就以非事務方式執行。

4)、MANDATORY

強制以事務方式執行,如果當前方法不在事務中,那麼會丟擲異常。

5)、NEVER

與MANDATORY相反,強制以非事務方式執行,如果當前方法在事務中,那麼會丟擲異常。

6)、REQUIRED_NEW

與REQUIRED不同的是,無論該方法當前是不是在事務中,都會為自己新建一個事務。如果當前已經在事務中,那麼會掛起父事務,為自己新建一個事務。父事務不影響它子事務的提交和回滾。

7)、NESTED

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

例如:

ServiceA {  
/**  
* 事務屬性配置為 PROPAGATION_REQUIRED  
*/  
void methodA() {  
try {  
//savepoint  
ServiceB.methodB(); //PROPAGATION_NESTED 級別  
} catch (SomeException) {  
// 執行其他業務, 如 ServiceC.methodC();  
}  
}  
}

也就是說ServiceB.methodB失敗回滾,那麼ServiceA.methodA也會回滾到savepoint點上,ServiceA.methodA可以選擇另外一個分支,比如ServiceC.methodC,繼續執行,來嘗試完成自己的事務。