springboot事務處理

zhaozhangxiao發表於2022-09-21


事務隔離級別

事務隔離性的4個級別,
1、讀未提交(Read Uncommitted)
讀未提交是資料庫應保證的最低的隔離性級別:事務中的修改,即使沒有提交,對其他事務也都是可見的。
讀未提交面臨髒讀的問題:事務可以讀取未提交的資料,而該資料可能在未來因回滾而消失。從效能上來說,讀未提交不會比其他的級別好太多,但卻缺乏其他級別的很多好處。除非真的有非常必要的理由,在實際應用中很少使用。
2、讀已提交(Read Committed)
讀已提交滿足前面提到的隔離性的簡單定義:一個事務所做的修改在最終提交以前,對其他事務是不可見的。換句話說,一旦提交,該事務所作的修改對其他正在進行中的事務就是可見的。
狹義上,讀已提交解決了髒讀的問題。這個級別有時候叫做不可重複讀,面臨不可重複讀的問題:兩次執行同樣的查詢,如果第二次讀到了其他事務提交的結果,則會得到不一樣的結果。

	大多數資料庫的預設隔離級別都是Read Committed,但MySQL不是。

3、可重複讀(Repeatable Read)
在讀已提交的基礎上,可重複讀解決了部分不可重複的問題:同一個事務中多次讀取同樣記錄結果是一致的。記錄指具體的資料行。

未能解決的那部分稱為幻讀:當某個事務在讀取目標範圍內的記錄時,另一個事務又在該範圍內插入了新的記錄,當之前的事務再次讀取該範圍的記錄時,會產生第一次讀取範圍時不存在的幻行(Phantom Row)。需要注意的是,只有插入會產生幻行。

MySQL的預設隔離級別是可重複讀,有幻讀問題。

4、可序列化(Serializable);
可序列化是最高的隔離級別:強制事務序列化執行。
可序列化解決了幻讀問題。簡單來說,可序列化會在目標範圍加獨佔鎖,將併發讀寫相同範圍資料的請求序列化。可序列化會導致大量的超時和鎖爭用問題,因此,實際應用中很少用到這個隔離級別,只有在非常需要確保資料的一致性而且可以接受沒有併發的情況下,才考慮採用該級別。


一、事務原理

基於鎖的併發控制中,4種隔離性級別的實現原理。重點關注讀鎖(read lock,或稱共享鎖)、寫鎖(write lock,或稱排它鎖)、範圍鎖(range lock)、鎖的持有時間等概念。
讀鎖又稱為共享鎖,共享鎖就是多個事務共享一把鎖,都能訪問到資料,但都只能讀不能修改。
寫鎖又稱為排他鎖,排他鎖和其他事務不能共存,如果一個事務獲取了一個資料行的排他鎖,其他的事務不可以再獲取到該資料行的任何鎖,獲取到排他鎖的資料行可以對行進行讀取和修改,沒有獲取到鎖的資料行 不能 讀取和修改。
mysql的innoDB引擎預設修改的語句都會加上排他鎖,比如update insert delete
範圍鎖針對目標範圍,一般是指sql語句中where約束的範圍

二、使springboot事務處理

1、事務隔離級別

在這裡插入圖片描述
我們可以看org.springframework.transaction.annotation.Isolation列舉類中定義了五個表示隔離級別的值:

public enum Isolation {
    DEFAULT(-1),
    READ_UNCOMMITTED(1),
    READ_COMMITTED(2),
    REPEATABLE_READ(4),
    SERIALIZABLE(8);
}
1、DEFAULT:這是預設值,表示使用底層資料庫的預設隔離級別。對大部分資料庫而言,通常這值就是:READ_COMMITTED。
2、READ_UNCOMMITTED:該隔離級別表示一個事務可以讀取另一個事務修改但還沒有提交的資料。該級別不能防止髒讀和不可重複讀,因此很少使用該隔離級別。
3、READ_COMMITTED:該隔離級別表示一個事務只能讀取另一個事務已經提交的資料。該級別可以防止髒讀,這也是大多數情況下的推薦值。
4、REPEATABLE_READ:該隔離級別表示一個事務在整個過程中可以多次重複執行某個查詢,並且每次返回的記錄都相同。即使在多次查詢之間有新增的資料滿足該查詢,這些新增的記錄也會被忽略。該級別可以防止髒讀和不可重複讀。
5、SERIALIZABLE:所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止髒讀、不可重複讀以及幻讀。但是這將嚴重影響程式的效能。通常情況下也不會用到該級別。

2、事務傳播

所謂事務的傳播行為是指,如果在開始當前事務之前,一個事務上下文已經存在,此時有若干選項可以指定一個事務性方法的執行行為。

我們可以看org.springframework.transaction.annotation.Propagation列舉類中定義了6個表示傳播行為的列舉值:

public enum Propagation {
    REQUIRED(0),
    SUPPORTS(1),
    MANDATORY(2),
    REQUIRES_NEW(3),
    NOT_SUPPORTED(4),
    NEVER(5),
    NESTED(6);
}
1、REQUIRED:如果當前存在事務,則加入該事務;如果當前沒有事務,則建立一個新的事務。預設型別
2、SUPPORTS:如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續執行。
3、MANDATORY:如果當前存在事務,則加入該事務;如果當前沒有事務,則丟擲異常。
4、REQUIRES_NEW:建立一個新的事務,如果當前存在事務,則把當前事務掛起。
5、NOT_SUPPORTED:以非事務方式執行,如果當前存在事務,則把當前事務掛起。
6、NEVER:以非事務方式執行,如果當前存在事務,則丟擲異常。
7、NESTED:如果當前存在事務,則建立一個事務作為當前事務的巢狀事務來執行;如果當前沒有事務,則該取值等價於REQUIRED。

指定方法:通過使用propagation屬性設定,例如:
@Transactional(propagation = Propagation.REQUIRED)

相關文章