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,繼續執行,來嘗試完成自己的事務。