事務管理對於企業應用來講是相當重要的,即便出現異常狀況,它也能夠保證數據的一致性。
Spring Framework對事務管理提供了一致的抽象,其特色以下:html
事務管理方式java
spring支持編程式事務管理和聲明式事務管理兩種方式。spring
編程式事務管理使用TransactionTemplate或者直接使用底層的PlatformTransactionManager。對於編程式事務管理,spring推薦使用TransactionTemplate。數據庫
聲明式事務管理創建在AOP之上的。其本質是對方法先後進行攔截,而後在目標方法開始以前建立或者加入一個事務,在執行完目標方法以後根據執行狀況提交或者回滾事務。聲明式事務最大的優勢就是不須要經過編程的方式管理事務,這樣就不須要在業務邏輯代碼中摻瑣事務管理的代碼,只需在配置文件中作相關的事務規則聲明(或經過基於@Transactional註解的方式),即可以將事務規則應用到業務邏輯中。編程
顯然聲明式事務管理要優於編程式事務管理,這正是spring倡導的非侵入式的開發方式。聲明式事務管理使業務代碼不受污染,一個普通的POJO對象,只要加上註解就能夠得到徹底的事務支持。和編程式事務相比,聲明式事務惟一不足地方是,後者的最細粒度只能做用到方法級別,沒法作到像編程式事務那樣能夠做用到代碼塊級別。可是即使有這樣的需求,也存在不少變通的方法,好比,能夠將須要進行事務管理的代碼塊獨立爲方法等等。後端
聲明式事務管理也有兩種經常使用的方式,一種是基於tx和aop名字空間的xml配置文件,另外一種就是基於@Transactional註解。顯然基於註解的方式更簡單易用,更清爽。數組
自動提交(AutoCommit)與鏈接關閉時的是否自動提交mybatis
自動提交併發
默認狀況下,數據庫處於自動提交模式。每一條語句處於一個單獨的事務中,在這條語句執行完畢時,若是執行成功則隱式的提交事務,若是
執行失敗則隱式的回滾事務。性能
對於正常的事務管理,是一組相關的操做處於一個事務之中,所以必須關閉數據庫的自動提交模式。不過,這個咱們不用擔憂,spring會將底層鏈接的自動提交特性設置爲false。
org/springframework/jdbc/datasource/DataSourceTransactionManager.java
1 // switch to manual commit if necessary. this is very expensive in some jdbc drivers, 2 // so we don't want to do it unnecessarily (for example if we've explicitly 3 // configured the connection pool to set it already). 4 if (con.getautocommit()) { 5 txobject.setmustrestoreautocommit(true); 6 if (logger.isdebugenabled()) { 7 logger.debug("switching jdbc connection [" + con + "] to manual commit"); 8 } 9 con.setautocommit(false); 10 }
有些數據鏈接池提供了關閉事務自動提交的設置,最好在設置鏈接池時就將其關閉。但C3P0沒有提供這一特性,只能依靠spring來設置。
由於JDBC規範規定,當鏈接對象創建時應該處於自動提交模式,這是跨DBMS的缺省值,若是須要,必須顯式的關閉自動提交。C3P0遵照這一規範,讓客戶代碼來顯式的設置須要的提交模式。
鏈接關閉時的是否自動提交
當一個鏈接關閉時,若是有未提交的事務應該如何處理?JDBC規範沒有說起,C3P0默認的策略是回滾任何未提交的事務。這是一個正確的策略,但JDBC驅動提供商之間對此問題並無達成一致。
C3P0的autoCommitOnClose屬性默認是false,沒有十分必要不要動它。或者能夠顯式的設置此屬性爲false,這樣會更明確。
基於註解的聲明式事務管理配置
spring-servlet.xml
1 <!-- transaction support--> 2 <!-- PlatformTransactionMnager --> 3 <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> 4 <property name="dataSource" ref="dataSource" /> 5 </bean> 6 <!-- enable transaction annotation support --> 7 <tx:annotation-driven transaction-manager="txManager" />
還要在spring-servlet.xml中添加tx名字空間
1 ... 2 xmlns:tx="http://www.springframework.org/schema/tx" 3 xmlns:aop="http://www.springframework.org/schema/aop" 4 xsi:schemaLocation=" 5 ... 6 7 http://www.springframework.org/schema/tx 8 9 10 http://www.springframework.org/schema/tx/spring-tx.xsd 11 12 ...
MyBatis自動參與到spring事務管理中,無需額外配置,只要org.mybatis.spring.SqlSessionFactoryBean引用的數據源與DataSourceTransactionManager引用的數據源一致便可,不然事務管理會不起做用。
另外須要下載依賴包aopalliance.jar放置到WEB-INF/lib目錄下。不然spring初始化時會報異常
java.lang.NoClassDefFoundError: org/aopalliance/intercept/MethodInterceptor
spring事務特性
spring全部的事務管理策略類都繼承自org.springframework.transaction.PlatformTransactionManager接口
1 public interface PlatformTransactionManager { 2 3 TransactionStatus getTransaction(TransactionDefinition definition) 4 throws TransactionException; 5 6 void commit(TransactionStatus status) throws TransactionException; 7 8 void rollback(TransactionStatus status) throws TransactionException; 9 }
其中TransactionDefinition接口定義如下特性:
事務隔離級別
隔離級別是指若干個併發的事務之間的隔離程度。TransactionDefinition 接口中定義了五個表示隔離級別的常量:
事務傳播行爲
所謂事務的傳播行爲是指,若是在開始當前事務以前,一個事務上下文已經存在,此時有若干選項能夠指定一個事務性方法的執行行爲。在TransactionDefinition定義中包括了以下幾個表示傳播行爲的常量:
事務超時
所謂事務超時,就是指一個事務所容許執行的最長時間,若是超過該時間限制但事務尚未完成,則自動回滾事務。在 TransactionDefinition 中以 int 的值來表示超時時間,其單位是秒。
默認設置爲底層事務系統的超時值,若是底層數據庫事務系統沒有設置超時值,那麼就是none,沒有超時限制。
事務只讀屬性
只讀事務用於客戶代碼只讀但不修改數據的情形,只讀事務用於特定情景下的優化,好比使用Hibernate的時候。
默認爲讀寫事務。
spring事務回滾規則
指示spring事務管理器回滾一個事務的推薦方法是在當前事務的上下文內拋出異常。spring事務管理器會捕捉任何未處理的異常,而後依據規則決定是否回滾拋出異常的事務。
默認配置下,spring只有在拋出的異常爲運行時unchecked異常時纔回滾該事務,也就是拋出的異常爲RuntimeException的子類(Errors也會致使事務回滾),而拋出checked異常則不會致使事務回滾。
能夠明確的配置在拋出那些異常時回滾事務,包括checked異常。也能夠明肯定義那些異常拋出時不回滾事務。
還能夠編程性的經過setRollbackOnly()方法來指示一個事務必須回滾,在調用完setRollbackOnly()後你所能執行的惟一操做就是回滾。
@Transactional註解
@Transactional屬性
屬性 | 類型 | 描述 |
---|---|---|
value | String | 可選的限定描述符,指定使用的事務管理器 |
propagation | enum: Propagation | 可選的事務傳播行爲設置 |
isolation | enum: Isolation | 可選的事務隔離級別設置 |
readOnly | boolean | 讀寫或只讀事務,默認讀寫 |
timeout | int (in seconds granularity) | 事務超時時間設置 |
rollbackFor | Class對象數組,必須繼承自Throwable | 致使事務回滾的異常類數組 |
rollbackForClassName | 類名數組,必須繼承自Throwable | 致使事務回滾的異常類名字數組 |
noRollbackFor | Class對象數組,必須繼承自Throwable | 不會致使事務回滾的異常類數組 |
noRollbackForClassName | 類名數組,必須繼承自Throwable | 不會致使事務回滾的異常類名字數組 |
用法
@Transactional 能夠做用於接口、接口方法、類以及類方法上。看成用於類上時,該類的全部 public 方法將都具備該類型的事務屬性,同時,咱們也能夠在方法級別使用該標註來覆蓋類級別的定義。
雖然 @Transactional 註解能夠做用於接口、接口方法、類以及類方法上,可是 Spring 建議不要在接口或者接口方法上使用該註解,由於這隻有在使用基於接口的代理時它纔會生效。另外, @Transactional 註解應該只被應用到 public 方法上,這是由 Spring AOP 的本質決定的。若是你在 protected、private 或者默承認見性的方法上使用 @Transactional 註解,這將被忽略,也不會拋出任何異常。
默認狀況下,只有來自外部的方法調用纔會被AOP代理捕獲,也就是,類內部方法調用本類內部的其餘方法並不會引發事務行爲,即便被調用方法使用@Transactional註解進行修飾。
1 @Transactional(readOnly = true) 2 public class DefaultFooService implements FooService { 3 4 public Foo getFoo(String fooName) { 5 // do something 6 } 7 8 // these settings have precedence for this method 9 //方法上註解屬性會覆蓋類註解上的相同屬性 10 @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW) 11 public void updateFoo(Foo foo) { 12 // do something 13 } 14 }
而事務的隔離級別有四種,隔離級別高的數據庫的可靠性高,但併發量低,而隔離級別低的數據庫可靠性低,但併發量高,系統開銷小
1.READ UNCIMMITTED(未提交讀)
事務中的修改,即便沒有提交,其餘事務也能夠看獲得,好比說上面的兩步這種現象就叫作髒讀,這種隔離級別會引發不少問題,如無必要,不要隨便使用
例子:仍是售票系統,小明和小花是售票員,他們分別是兩個不一樣窗口的員工,如今售票系統只剩下3張票,此時A來小華這裏買3張票,B來小明買票,小華查到餘票還有就給接了訂單,就要執行第三步的時候,小明接到B的請求查詢有沒有餘票。看到小華賣出了3張票,因而拒絕賣票。可是小華系統出了問題,第三步執行失敗,數據庫爲保證原子性,數據進行了回滾,也就是說一張票都沒賣出去。
總結:這就是事務還沒提交,而別的事務能夠看到他其中修改的數據的後果,也就是髒讀。
2.READ COMMITTED(提交讀)
大多數數據庫系統的默認隔離級別是READ COMMITTED,這種隔離級別就是一個事務的開始,只能看到已經完成的事務的結果,正在執行的,是沒法被其餘事務看到的。這種級別會出現讀取舊數據的現象
例子:仍是小明小華銷售員,餘票3張,A來小華那裏請求3張訂票單,小華接受訂單,要賣出3張票,上面的銷售步驟執行中的時候,B也來小明那裏買票,因爲小華的銷售事務執行到一半,小明事務沒有看到小華的事務執行,讀到的票數是3,準備接受訂單的時候,小華的銷售事務完成了,此時小明的系統變成顯示0張票,小明剛想按下鼠標點擊接受訂單的手又連忙縮了回去。
總結:這就是小華的事務執行到一半,而小明看不到他執行的操做,因此看到的是舊數據,也就是無效的數據
3.REPEATABLE READ(可重複讀)
REPEATABLE READ解決了髒讀的問題,該級別保證了每行的記錄的結果是一致的,也就是上面說的讀了舊數據的問題,可是卻沒法解決另外一個問題,幻行,顧名思義就是忽然蹦出來的行數據。指的就是某個事務在讀取某個範圍的數據,可是另外一個事務又向這個範圍的數據去插入數據,致使屢次讀取的時候,數據的行數不一致。
例子:銷售部門有規定,若是銷售記錄低於規定的值,要扣工資,此時經理在後端控制檯查看了一下小明的銷售記錄,發現銷售記錄達不到規定的次數,內心暗喜,準備打印好銷售清單,義正詞嚴和小明提出,沒想到打印出來的時候發現銷售清單裏面銷售數量增多了幾條,剛恰好達到要求,氣的經理撕了清單紙。原來是小明在就要打印的瞬間賣出了幾張票,所以避過了減工資的血光之災。
總結:雖然讀取同一條數據能夠保證一致性,可是卻不能保證沒有插入新的數據
4.SERIALIZABLE(可串行化)
SERIALIZABLE是最高的隔離級別,它經過強制事務串行執行(注意是串行),避免了前面的幻讀狀況,因爲他大量加上鎖,致使大量的請求超時,所以性能會比較底下,再特別須要數據一致性且併發量不須要那麼大的時候纔可能考慮這個隔離級別
轉自https://www.cnblogs.com/yepei/p/4716112.html