Spring事務
spring針對不同的dao層框架,提供接口不同的實現類,常用的有兩個
事務管理器 | 使用場景 |
---|---|
jdbc.datasource.datasourceTransactionManager | 用於Spring對於JDBC的抽象的支持,也可以適用於mybatis進行持久化的場景 |
orm.hibernate3.HibernateTransactionManager | 用於hibernate3 進行持久化 |
一、事務的五邊形屬性
1. 傳播行爲
七種傳播行爲:
傳播行爲 | 含義 |
---|---|
PROPAGATION_REQUIRED — required | 默認的事務類型, 表示當前方法必須運行在事務中。如果當前事務存在,方法將會在該事務中運行。否則,會啓動一個新的事務 |
PROPAGATION_SUPPORTS —-support | 表示當前方法不需要事務上下文,但是如果存在當前事務的話,那麼該方法會在這個事務中運行 |
PROPAGATION_REQUIRED_NEW —-require_new | 表示當前方法必須運行在它自己的事務中,一個新的事務將被啓動。如果存在當前事務,在該方法執行期間,當前事務會被掛起, 意味着 啓動一個新的, 不依賴於環境的 “內部” 事務. 這個事務將被完全 commited 或 rolled back 而不依賴於外部事務, 它擁有自己的隔離範圍, 自己的鎖, 等等. 當內部事務開始執行時, 外部事務將被掛起, 內務事務結束時, 外部事務將繼續執行. |
PROPAGATION_NESTED —- nested | 表示如果當前已經存在一個事務,那麼該方法將會在嵌套事務中運行。如果當前事務不存在,那麼其行爲與PROPAGATION_REQUIRED一樣。注意的是這種傳播屬性的嵌套事務意味着新啓動的內層事務依賴於外部事務,外層事務的回滾可以引起內層事務的回滾。潛套事務開始執行時, 它將取得一個 savepoint. 如果這個嵌套事務失敗, 我們將回滾到此 savepoint. 潛套事務是外部事務的一部分, 只有外部事務提交後它纔會被提交 |
PROPAGATION_NOT_SUPPORTED—- not support | 表示該方法不應該運行在事務中。如果存在當前事務,在該方法運行期間,當前事務將被掛起。 |
PROPAGATION_NEVER —– never | 表示當前方法不應該運行在事務上下文中。如果當前正有一個事務在運行,則會拋出異常 |
PROPAGATION_MANDATORY —mandatory | 表示該方法必須在事務中運行,如果當前事務不存在,則會拋出一個異常 |
PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大區別在於, PROPAGATION_REQUIRES_NEW 完全是一個新的事務, 而 PROPAGATION_NESTED 則是外部事務的子事務, 如果外部事務 commit, 潛套事務也會被 commit, 這個規則同樣適用於 roll back.
2. 隔離規則
- 併發事務引起的問題
(1)髒讀(Dirty reads)——髒讀發生在一個事務讀取了另一個事務改寫但尚未提交的數據時。如果改寫在稍後被回滾了,那麼第一個事務獲取的數據就是無效的
(2)不可重複讀(Nonrepeatable read)——不可重複讀發生在一個事務執行相同的查詢兩次或兩次以上,但是每次都得到不同的數據時。這通常是因爲另一個併發事務在兩次查詢期間進行了更新
(3) 幻讀(Phantom read)——幻讀與不可重複讀類似。它發生在一個事務(T1)讀取了幾行數據,接着另一個併發事務(T2)插入了一些數據時。在隨後的查詢中,第一個事務(T1)就會發現多了一些原本不存在的記錄
隔離級別 | 含義 |
---|---|
ISOLATION_DEFAULT | 使用後端數據庫默認的隔離級別,一般是 REPEATABLE_READ 可重複讀 |
ISOLATION_READ_UNCOMMITTED 未提交讀 | 最低的隔離級別,允許讀取尚未提交的數據變更,可能會導致髒讀、幻讀或不可重複讀 |
ISOLATION_READ_COMMITTED 提交讀 | 允許讀取併發事務已經提交的數據,可以阻止髒讀,但是幻讀或不可重複讀仍有可能發生 |
ISOLATION_REPEATABLE_READ 可重複讀 | 對同一字段的多次讀取結果都是一致的,除非數據是被本身事務自己所修改,可以阻止髒讀和不可重複讀,但幻讀仍有可能發生 |
ISOLATION_SERIALIZABLE 串行化 | 最高的隔離級別,完全服從ACID的隔離級別,確保阻止髒讀、不可重複讀以及幻讀,也是最慢的事務隔離級別,因爲它通常是通過完全鎖定事務相關的數據庫表來實現的 |
3. 只讀 read-only
事務的第三個特性是它是否爲只讀事務。如果 事務只對後端的數據庫進行讀操作,數據庫可以利用事務的只讀特性來進行一些特定的優化。通過將事務設置爲只讀,你就可以給數據庫一個機會,讓它應用它認爲合適的優化措施
4. 事務超時
爲了使應用程序很好地運行,事務不能運行太長的時間。因爲事務可能涉及對後端數據庫的鎖定,所以長時間的事務會不必要的佔用數據庫資源。事務超時就是事務的一個定時器,在特定時間內事務如果沒有執行完畢,那麼就會自動回滾,而不是一直等待其結束
5. 回滾規則
事務五邊形的最後一個方面是一組規則,這些規則定義了哪些異常會導致事務回滾而哪些不會。默認情況下,事務只有遇到運行期異常時纔會回滾,而在遇到檢查型異常時不會回滾(這一行爲與EJB的回滾行爲是一致的)
但是你可以聲明事務在遇到特定的檢查型異常時像遇到運行期異常那樣回滾。同樣,你還可以聲明事務遇到特定的異常不回滾,即使這些異常是運行期異常。
二、 spring事務管理兩種方式
第一種 編程式事務管理
直接通過編碼使用Spring 的 TransactionTemplate來添加事務性邊界,適用於完全的控制事務的邊界,但是具有侵入性
// 執行事務模板的execute方法進行事務管理
public void saveUser(finnal User user){
transactionTemplate.execute(
new TransactionCallback(){
public Object doTransaction(TransactionStatus status){
try{
userDao.saveUser(user);
} catch (RuntimeException e){
status.setRollbackOnly(); // 發生異常,設置回滾事務
throw e;
}} );
}
第二種 聲明式事務管理
(1) 基於xml配置文件實現
<!-- 第一步 配置事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 注入dataSource -->
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 第二步 配置事務增強 -->
<tx:advice id="txadvice" transaction-manager="transactionManager">
<!-- 做事務操作 -->
<tx:attributes>
<!-- 設置進行事務操作的方法匹配規則 -->
<tx:method name="account*" propagation="REQUIRED" read-only = "true"/>
</tx:attributes>
</tx:advice>
<!-- 第三步 配置切面 -->
<aop:config>
<!-- 切入點 -->
<aop:pointcut expression="execution(* cn.itcast.service.OrdersService.*(..))" id="pointcut1"/>
<!-- 切面 -->
<aop:advisor advice-ref="txadvice" pointcut-ref="pointcut1"/>
</aop:config>
(2) 基於註解實現
<!-- 第一步配置事務管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 第二步 開啓事務註解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 第三步, 在實際的代碼中添加註解,在類的上面添加註解意味着類中的所有方法全部都會納入到事務的管理之中 -->
@Transactional
public class OrdersService {
......
.....
}
本博客參考了文章: http://www.mamicode.com/info-detail-1248286.html
說明: 本文大部分內容都是跟隨者傳播智課的教學視頻學習而來,可以看做是翻譯文章,只是自己吸收之後又書寫一遍,加深自己的知識理解。