一、簡述事務是恢復和并發控制的基本單位。
事務(Transaction)是訪問并可能更新數據庫中各種數據項的一個程序執行單元(unit)。事務通常由高級數據庫操縱語言或編程語言(如 SQL、C++ 或 Java)書寫的用戶程序的執行所引起,并用形如 begin transaction 和 end transaction 語句(或函數調用)來界定。事務由事務開始(begin transaction)和事務結束(end transaction)之間執行的全體操作組成。例如:在關系數據庫中,一個事務可以是一條 SQL 語句,一組 SQL 語句或整個程序。
事務隔離級別定義了在一個事務中,哪些數據是對當前執行的語句“可見”的。在并發訪問數據庫時,事務隔離級別定義了多個事務之間對于同個目標數據源訪問時的可交叉程度。
二、可交叉程度
1??Dirty Read(臟讀) 看到的數據則是不正確的
2??Non-repeatable Read(不可重復讀) 兩次讀取到的數據不同
3??Phantom Read(幻讀) 發現多出來一條數據
三、事務隔離級別(Isolation)
JDBC 規范增加了隔離級別,來滿足了 SQL:2003 定義的 4 種事務隔離級別。在安裝MySQL時,安裝默認的隔離級別就是:可重復讀。
可以通過 select @@global.tx_isolation;
來查看當前隔離級別。隔離級別從最寬松到最嚴格,排序如下所示:
1??TRANSACTION_NONE
這意味著當前的 JDBC 驅動不支持事務,也意味著這個驅動不符合 JDBC 規范。
2??READ_UNCOMMITTED(讀未提交)
允許事務看到其它事務修改了但未提交的數據,這意味著有可能是臟讀、不可重復讀或者幻讀。
3??READ_COMMITTED(讀提交)
一個事務在未提交之前,所做的修改不會被其它事務所看見。這能避免臟讀,但避免不了不可重復讀和幻讀。
4??REPEATABLE_READ(可重復讀取) MySQL默認的事務隔離級別
避免了臟讀和不可重復讀,但幻讀依然是有可能發生的。
5??SERIALIZABLE(序列化)
避免了臟讀、不可重復讀以及幻讀。
三、Propagation:用來枚舉事務的傳播行為
所謂事務的傳播行為就是多個事務方法相互調用時,事務如何在這些方法間傳播。Spring 支持 7 種事務傳播行為,默認為 REQUIRED。
1??REQUIRED
@Transactional(propagation=Propagation.REQUIRED)
如果當前有事務,加入到這個事務中。如果當前沒有事務,就新建一個事務。
2??REQUIRES_NEW
@Transactional(propagation=Propagation.REQUIRES_NEW)
不管是否存在事務,都創建一個新的事務,原來的掛起,新的執行完畢,繼續執行老的事務。表示當前方法必須運行在它自己的事務中。如果使用 JTATransactionManager 的話,則需要訪問 TransactionManager。
3??MANDATORY
@Transactional(propagation=Propagation.MANDATORY)
表示該方法必須在事務中運行,如果當前不存在事務,則會拋出一個異常。不會主動開啟一個事務。
4??NEVER
@Transactional(propagation=Propagation.NEVER)
表示該方法不應該運行在事務上下文中,如果當前正有一個事務在運行,則會拋出異常。(與Propagation.MANDATORY相反)。
5??SUPPORTS
@Transactional(propagation=Propagation.SUPPORTS)
表示當前方法不需要事務上下文,但是如果存在當前事務的話,那么這個方法會在這個事務中運行。
6??NOT_SUPPORTED
@Transactional(propagation=Propagation.NOT_SUPPORTED)
表示該方法不應該運行在事務中,如果存在當前事務,在該方法運行期間,當前事務將被掛起。如果使用 JTATransactionManager 的話,則需要訪問 TransactionManager。
7??NESTED
@Transactional(propagation=Propagation.NESTED)
表示如果當前已經存在事務,那么該方法將會在嵌套事務中運行。嵌套的事務可以獨立于當前事務進行單獨地提交或回滾。如果當前不存在事務,那么其行為等價于 Propagation.REQUIRED。嵌套事務一個非常重要的概念就是內層事務依賴于外層事務。外層事務失敗時,會回滾內層事務所做的動作。而內層事務操作失敗并不會引起外層事務的回滾。
綜上所述,NESTED 和 REQUIRES_NEW 非常相似,都是開啟一個屬于它自己的新事務。使用 REQUIRES_NEW 時,內層事務與外層事務就像兩個獨立的事務一樣,一旦內層事務進行了提交后,外層事務不能對其進行回滾。當內部事務開始執行時, 外部事務將被掛起,內務事務結束時,外部事務將繼續執行。兩個事務互不影響,兩個事務不是一個真正的嵌套事務,同時它還需要 JTA 事務管理器的支持。
使用 NESTED 時,外層事務的回滾可以引起內層事務的回滾。而內層事務的異常并不會導致外層事務的回滾,它是一個真正的嵌套事務。嵌套事務開始執行時,它將取得一個 savepoint,如果這個嵌套事務失敗,將回滾到此 savepoint。嵌套事務是外部事務的一部分,只有外部事務結束后它才會被提交。