1. TransactionDefinition接口中定義五個隔離級別:
ISOLATION_DEFAULT 這是一個PlatfromTransactionManager默認的隔離級別,使用數據庫默認的事務隔離級別.另外四個與JDBC的隔離級別相對應;
ISOLATION_READ_UNCOMMITTED 這是事務最低的隔離級別,它充許別外一個事務可以看到這個事務未提交的數據。這種隔離級別會產生臟讀,不可重復讀和幻像讀。
ISOLATION_READ_COMMITTED 保證一個事務修改的數據提交后才能被另外一個事務讀取。另外一個事務不能讀取該事務未提交的數據。這種事務隔離級別可以避免臟讀出現,但是可能會出現不可重復讀和幻像讀。
ISOLATION_REPEATABLE_READ 這種事務隔離級別可以防止臟讀,不可重復讀。但是可能出現幻像讀。它除了保證一個事務不能讀取另一個事務未提交的數據外,還保證了避免下面的情況產生(不可重復讀)。
ISOLATION_SERIALIZABLE 這是花費最高代價但是最可靠的事務隔離級別。事務被處理為順序執行。除了防止臟讀,不可重復讀外,還避免了幻像讀。
Dirty reads(臟讀)。也就是說,比如事務A的未提交(還依然緩存)的數據被事務B讀走,如果事務A失敗回滾,會導致事務B所讀取的的數據是錯誤的。
non-repeatable reads(數據不可重復讀)。比如事務A中兩處讀取數據-total-的值。在第一讀的時候,total是100,然后事務B就把total的數據改成 200,事務A再讀一次,結果就發現,total竟然就變成200了,造成事務A數據混亂。
phantom reads(幻象讀數據),這個和non-repeatable reads相似,也是同一個事務中多次讀不一致的問題。但是non-repeatable reads的不一致是因為他所要取的數據集被改變了(比如total的數據),但是phantom reads所要讀的數據的不一致卻不是他所要讀的數據集改變,而是他的條件數據集改變。比如Select account.id where account.name=”ppgogo*”,第一次讀去了6個符合條件的id,第二次讀取的時候,由于事務b把一個帳號的名字由”dd”改成”ppgogo1”,結果取出來了7個數據。
3. 在TransactionDefinition接口中定義了七個事務傳播行為:
1)?PROPAGATION_REQUIRED 如果存在一個事務,則支持當前事務。如果沒有事務則開啟一個新的事務。這是我們使用最多的事務傳播行為?
例如方法A中調用方法B,如果在調用A時沒有事務則開啟一個事務,而對于B則會加入到A的事務中。?
使用spring聲明式事務,spring使用AOP來支持聲明式事務,會根據事務屬性,自動在方法調用之前決定是否開啟一個事務,并在方法執行之后決定事務提交或回滾事務.
2)PROPAGATION_SUPPORTS 如果存在一個事務,支持當前事務。如果沒有事務,則非事務的執行。但是對于事務同步的事務管理器,PROPAGATION_SUPPORTS與不使用事務有少許不同。
3)PROPAGATION_MANDATORY 如果已經存在一個事務,支持當前事務。如果沒有一個活動的事務,則拋出異常throw new IllegalTransactionStateException(“Transaction propagation ‘mandatory’ but no existing transaction found”);。
4)PROPAGATION_REQUIRES_NEW 總是開啟一個新的事務。如果一個事務已經存在,則將這個存在的事務掛起。使用PROPAGATION_REQUIRES_NEW,需要使用 JtaTransactionManager作為事務管理器。
5)PROPAGATION_NOT_SUPPORTED 總是非事務地執行,并掛起任何存在的事務。使用PROPAGATION_NOT_SUPPORTED,也需要使用JtaTransactionManager作為事務管理器。
6)PROPAGATION_NEVER 總是非事務地執行,如果存在一個活動事務,則拋出異常;
7)PROPAGATION_NESTED如果一個活動的事務存在,則運行在一個嵌套的事務中. 如果沒有活動事務, 則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執行。這是一個嵌套事務,使用JDBC 3.0驅動時,僅僅支持DataSourceTransactionManager作為事務管理器。需要JDBC 驅動的java.sql.Savepoint類。有一些JTA的事務管理器實現可能也提供了同樣的功能。使用PROPAGATION_NESTED,還需要把PlatformTransactionManager的nestedTransactionAllowed屬性設為true;而 nestedTransactionAllowed屬性值默認為false;
使用JDBC的時候開啟事務使用Connection,而使用Hibernate時開啟事務使用的是Session。所以如果我們使用傳統的事務編程策略時,程序代碼必須和具體的事務操作代碼耦合。這樣在不同的事務策略之間切換時開發者必須手動改代碼。而如果使用Spring來管理事務則不會出現這種情況。
Spring事務策略是通過PlatformTransactionManager接口實現的,它是整個Spring事務的核心。它是對事務策略的一個高度抽象,不依賴于任何具體的事務策略,而對于底層的具體的事務策略它相應的有不同的實現類。而對于不同的事務策略的切換通常由Spring容器來負責管理,應用程序既無須與具體的事務API耦合,也無須與特定的實現類耦合而將應用和持久化技術,事務API徹底分離開來。
Spring事務管理的策略模式體現在哪?PlatformTransactionManager代表事務管理接口,但它并不知道底層到底如何管理事務的,而它只要求事務管理提供開始事務(getTransaction(TransactionDefinition definition)),提交事務(commit())和回滾事務(rollback())三個方法,具體的實現交給子類來完成。
源碼:
publicinterfacePlatformTransactionManager{//獲得事務TransactionStatus? getTransaction(TransactionDefinition definition)throwsTransactionException;//事務提交voidcommit(TransactionStatus status)throwsTransactionException;//事務回滾voidrollback(TransactionStatus status)throwsTransactionException ;}
在核心接口PlatformTransactionManager中,方法getTransaction(TransactionDefinition definition)中它接受一個TransactionDefinition對象返回一個TransactionStatus。TransactionStatus對象表示一個事務,被關聯在當前執行的線程上。返回的事務可以是個新事務,也可以是個已經存在的事務對象
TransactionDefinition接口必須指定如下的幾個屬性值:
事務隔離
事務傳播
事務超時(即事務最長持續時間)
只讀狀態(Hibernate很有用的優化)
TransactionStatus:代表事務本身,它提供了通用的事務管理如控制事務的執行和查詢事務狀態的方法。?
源碼:
publicinterfaceTransactionStatus{booleanisNewTransaction();//是否為新建事務voidsetRollbackOnly();//設置事務回滾booleanisRollBackOnly();//查詢事務是否已有回滾標志}
幾個類之間的關系:?
Spring具體的事務管理由PlatformTransactionManager的不同實現類來完成,在Spring容器中配置PlatformTransactionManager Bean時,必須針對不同的環境來配置不同的實現類。
下面分別展示了在JDBC和Hibernate中配置PlatformTransactionManager對應的實現類。?
JDBC
Hibernate
對于Spring通過的兩種事務管理。編程式的事務管理程序直接從容器中獲取transactionManager Bean,該Bean總是PlatformTransactionManager的實例,所以可以使用它的三個方法來管理事務。而對于聲明式事務管理只需要要在XML配置文件中配置事務代理即可,在目標方法中開發者無需編寫額外的代碼,不依賴Spring或任何其他事務的API。
Spring提供了tx:命名空間來配置事務管理,tx:下的配置事務增強處理,最后使用元素啟用自動代理。?
元素除了需要transaction-manager之外,還需要子元素,該子元素包含多個子元素,用來配置事務的屬性。?
的重要屬性:
propagation:事務傳播行為 默認是REQUIRED
isolation:事務隔離級別?
timeout:超時時間