資料庫事務隔離級別以及spring傳播屬性
阿新 • • 發佈:2019-08-08
資料庫事務隔離級別
資料庫有四種事務隔離級別
- 讀未提交(Read uncommitted)
- 讀已提交(Read committed)
- 可重複讀(Repeatable read)
- 序列化(Serializable)
以上事務隔離級別依次遞增,但是效能依次遞減。
mysql支援以上四種隔離級別,其預設是:可重複讀(Repeatable read)。
oracle資料庫支援READ COMMITTED 和 SERIALIZABLE兩種。
oracle和PostgreSQL預設是:讀已提交(Read committed)。
隔離級別詳解
以上四種隔離分別會出現以下問題
隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
---|---|---|---|
讀未提交(Read uncommitted) | 可能 | 可能 | 可能 |
讀已提交(Read committed) | 不可能 | 可能 | 可能 |
可重複讀(Repeatable read) | 不可能 | 不可能 | 可能 |
序列化(Serializable) | 不可能 | 不可能 | 不可能 |
-
髒讀:
T1修改資料後未提交之前,T2可以訪問修改後的資料。 -
不可重複讀:
T1:讀取userid=1的salary=1000;
T2:將userid=1的salary改為2000並提交;
T1:此時再次讀取userid=1的記錄,則讀取不到salary=1000了,這既是不可重複讀。 -
幻讀:
T1:select id=1,resultset=null,此時準備插入一條;
T1:insert id=1 ,報錯。
在這種情況下,T1按照邏輯本來是預計成功的,但是卻報錯主鍵衝突,此時T1就產生了幻讀,彷彿看花眼出現幻象了一般。 -
序列化:
每個事務排隊執行。
序列話為什麼不會出現幻讀?因為會鎖定索引。
還是上面幻讀的例子,T1查詢的時候,因為是主鍵查詢,資料庫會自動給索引加上鎖(索引加鎖,與具體資料無關),所以T2的操作會失敗,T1的插入會成功。當然如果我們在可重複讀模式下,通過select for update 是也可以達到Serializable的效果。
Spring事務傳播特性
事務傳播特性是指,當多個方法形成一個呼叫鏈時,事務是如何傳播的(如A方法中呼叫了B方法,那麼事務是以哪種方式傳播給B)。
- PROPAGATION_REQUIRED(spring預設):如果當前存在事務,則加入該事務;如果當前沒有事務,則建立一個新的事務。
- PROPAGATION_SUPPORTS:如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續執行。
- PROPAGATION_MANDATORY:如果當前存在事務,則加入該事務;如果當前沒有事務,則丟擲異常。
- PROPAGATIONREQUIRESNEW:建立一個新的事務,如果當前存在事務,則把當前事務掛起。
- PROPAGATIONNOTSUPPORTED:以非事務方式執行,如果當前存在事務,則把當前事務掛起。
- PROPAGATION_NEVER:以非事務方式執行,如果當前存在事務,則丟擲異常。
- PROPAGATIONNESTED:如果當前存在事務,則建立一個事務作為當前事務的巢狀事務來執行;如果當前沒有事務,則該取值等價於PROPAGATIONREQUIRED。
以上七中傳播特性中,前六種屬於EJB,被spring引進;後一種是spring特有的。
spring事務隔離級別
- ISOLATION_DEFAULT:使用後端資料庫預設的隔離級別。
- ISOLATION_READ_UNCOMMITTED:允許讀取尚未提交的更改。可能導致髒讀、幻影讀或不可重複讀。
- ISOLATION_READ_COMMITTED:允許從已經提交的併發事務讀取。可防止髒讀,但幻影讀和不可重複讀仍可能會發生。
- ISOLATION_REPEATABLE_READ:對相同欄位的多次讀取的結果是一致的,除非資料被當前事務本身改變。可防止髒讀和不可重複讀,但幻讀仍可能發生。
- ISOLATION_SERIALIZABLE:完全服從ACID的隔離級別,確保不發生髒讀、不可重複讀