一般我們說事務,都是用一個術語來描述事務:ACID。也就事務的四個特性:原子性(Atomic),一致性(Consistent),隔離性(Isolated),持久性(Durable). 原子性:事務是由一個或多個活動所組成的一個工作單元(比如一個方法里有增刪改)。原子性保證這個事務中所有操作要么全部完成,要么全部不發生。也就是說如果所有活動都完成了,事務就成功了,如果有一個失敗了,事務就失敗了并且進行回滾。 一致性:一旦事務完成(不管成功還是失?。?,系統就必須確保所建模的業務必須處于一致的狀態(比如,取錢100成功,銀行卡就少100。失敗,銀行卡里錢就不少)?,F實的數據不應該被損壞。 隔離性:多個用戶同時操作相同數據,但是用戶之間的操作不應該相互影響。因此事務應該被彼此隔離,避免發生同步讀寫相同數據的情況,造成用戶讀寫數據混亂,造成數據損壞。 持久性:事務一旦完成,數據就應該持久化,一般會存儲到數據庫或者其他形式的持久化存儲中。
SPRing并不直接管理事務,而是提供了多種事務管理器,他們將事務管理的職責委托給JTA或者其他持久化機制所提供的平臺相關的事務實現。Spring事務管理器的接口是org.springframework.transaction.PlatformTransactionManager(在spring-tx.jar包中)。通過這個接口,spring為各個平臺提供了對應的事務管理器。如:org.springframework.jdbc.datasource.DataSourceTransactionManager用于對JDBC抽象的支持,也可用于使用Ibtais進行持久化。 PlatformTransactionManager接口代碼如下:
package org.springframework.transaction;public interface PlatformTransactionManager { //由TransactionDefinition得到TransactionStatus對象 TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException; //事務提交 void commit(TransactionStatus status) throws TransactionException; //事務回滾 void rollback(TransactionStatus status) throws TransactionException;}在spring中有兩種事務形式,編碼式和聲明式。一般我們采用聲明式,因為編碼式對代碼有侵入,聲明式解耦性比較好。 聲明式事務是通過事務屬性(transaction attribute)來定義的。事務屬性包含了5個方面,傳播行為,隔離級別,事務超時,回滾規則,是否只讀?
上面講到的事務管理器接口PlatformTransactionManager通過getTransaction(TransactionDefinition definition)方法來得到事務,這個方法里面的參數是TransactionDefinition類,這個類就定義了一些基本的事務屬性。
事務的傳播行為:
事務的第一個方面是傳播行為(propagation behavior)。當事務方法被另一個事務方法調用時,必須指定事務應該如何傳播。例如:方法可能繼續在現有事務中運行,也可能開啟一個新事務,并在自己的事務中運行。Spring定義了七種傳播行為:
PROPAGATION_REQUIRED 表示當前方法必須運行在事務中。如果當前事務存在,方法將會在該事務中運行。否則,會啟動一個新的事務
PROPAGATION_SUPPORTS 表示當前方法不需要事務上下文,但是如果存在當前事務的話,那么該方法會在這個事務中運行
PROPAGATION_MANDATORY 表示該方法必須在事務中運行,如果當前事務不存在,則會拋出一個異常
PROPAGATION_REQUIRED_NEW 表示當前方法必須運行在它自己的事務中。一個新的事務將被啟動。如果存在當前事務,在該方法執行期間,當前事務會被掛起。如果使用JTATransactionManager的話,則需要訪問TransactionManager
PROPAGATION_NOT_SUPPORTED 表示該方法不應該運行在事務中。如果存在當前事務,在該方法運行期間,當前事務將被掛起。如果使用JTATransactionManager的話,則需要訪問TransactionManager
PROPAGATION_NEVER 表示當前方法不應該運行在事務上下文中。如果當前正有一個事務在運行,則會拋出異常
PROPAGATION_NESTED 表示如果當前已經存在一個事務,那么該方法將會在嵌套事務中運行。嵌套的事務可以獨立于當前事務進行單獨地提交或回滾。如果當前事務不存在,那么其行為與PROPAGATION_REQUIRED一樣。注意各廠商對這種傳播行為的支持是有所差異的??梢詤⒖假Y源管理器的文檔來確認它們是否支持嵌套事務
事務的隔離級別: 事務的第二個維度就是隔離級別(isolation level)。隔離級別定義了一個事務可能受其他并發事務影響的程度。 在典型的應用程序中,多個事務并發運行,經常會操作相同的數據來完成各自的任務。并發雖然是必須的,但可能會導致一下的問題。
臟讀(Dirty reads)——臟讀發生在一個事務讀取了另一個事務改寫但尚未提交的數據時。如果改寫在稍后被回滾了,那么第一個事務獲取的數據就是無效的。 不可重復讀(Nonrepeatable read)——不可重復讀發生在一個事務執行相同的查詢兩次或兩次以上,但是每次都得到不同的數據時。這通常是因為另一個并發事務在兩次查詢期間進行了更新。 幻讀(Phantom read)——幻讀與不可重復讀類似。它發生在一個事務(T1)讀取了幾行數據,接著另一個并發事務(T2)插入了一些數據時。在隨后的查詢中,第一個事務(T1)就會發現多了一些原本不存在的記錄。
在理想情況下,事務之間是完全隔離的,從而防止問題的發生,但是完全的隔離會導致性能下降。因為這會涉及到鎖定數據庫的記錄,侵占性的鎖會阻礙并發性,要求事務必須等待來完成各自的工作。所以考慮的性能問題,所以程序有時需要在事務上有一定的靈活性。因此有多個事務隔離級別。 ISOLATION_DEFAULT 使用后端數據庫默認的隔離級別 ISOLATION_READ_UNCOMMITTED 最低的隔離級別,允許讀取尚未提交的數據變更,可能會導致臟讀、幻讀或不可重復讀 ISOLATION_READ_COMMITTED 允許讀取并發事務已經提交的數據,可以阻止臟讀,但是幻讀或不可重復讀仍有可能發生 ISOLATION_REPEATABLE_READ 對同一字段的多次讀取結果都是一致的,除非數據是被本身事務自己所修改,可以阻止臟讀和不可重復讀,但幻讀仍有可能發生 ISOLATION_SERIALIZABLE 最高的隔離級別,完全服從ACID的隔離級別,確保阻止臟讀、不可重復讀以及幻讀,也是最慢的事務隔離級別,因為它通常是通過完全鎖定事務相關的數據庫表來實現的
事務的第三個特性是它是否為只讀事務。如果事務只對后端的數據庫進行該操作,數據庫可以利用事務的只讀特性來進行一些特定的優化。通過將事務設置為只讀,你就可以給數據庫一個機會,讓它應用它認為合適的優化措施。
為了使應用程序很好地運行,事務不能運行太長的時間。因為事務可能涉及對后端數據庫的鎖定,所以長時間的事務會不必要的占用數據庫資源。事務超時就是事務的一個定時器,在特定時間內事務如果沒有執行完畢,那么就會自動回滾,而不是一直等待其結束。
事務五邊形的最后一個方面是一組規則,這些規則定義了哪些異常會導致事務回滾而哪些不會。默認情況下,事務只有遇到運行期異常時才會回滾,而在遇到檢查型異常時不會回滾(這一行為與EJB的回滾行為是一致的) 但是你可以聲明事務在遇到特定的檢查型異常時像遇到運行期異常那樣回滾。同樣,你還可以聲明事務遇到特定的異常不回滾,即使這些異常是運行期異常。
上面講到的調用PlatformTransactionManager接口的getTransaction()的方法得到的是TransactionStatus接口的一個實現,源碼如下:
package org.springframework.transaction;public interface TransactionStatus extends SavepointManager { //是否是新事務 boolean isNewTransaction(); // 是否有恢復點 boolean hasSavepoint(); // 設置為只回滾 void setRollbackOnly(); // 是否為只回滾 boolean isRollbackOnly(); //清楚session void flush(); // 是否已完成 boolean isCompleted();}新聞熱點
疑難解答