事務的基本屬性(ACID):
- 原子性(Atomicity):事務是一個原子單位,要麼全部執行,要麼全部不執行
- 一致性(Consistency):事務開始前和結束後,資料庫的完整性約束沒有被破壞。
- 隔離性(Isolation):併發的事務是相互隔離的。
- 永續性(Durability):事務完成後,該事務所對資料庫所做的更改持久的儲存在資料庫之中,並不會被回滾。
事務的併發問題:
髒讀:讀取了未提交的資料。例如事務1修改某個欄位的值,但未commit到資料庫,然後事務2讀取了該值,後來事務1撤銷了對該欄位的更新或者是更改該欄位的值才commit到資料庫。這樣事務2讀到的就是髒資料。
不可重複讀:在資料庫訪問中,一個事務範圍內的兩次相同的查詢卻返回了不同的資料。例如事務1讀取了某一資料,事務2讀取並修改了該資料,事務1為了對讀取值進行驗證而重新讀取,卻得到了不同的結果。
幻讀:事務1對錶中的資料進行修改,修改涉及了表中全部的資料行。同時,事務2想這個表插入了一行新資料。操作事務1的使用者就會發現表中還有沒有修改的資料行,彷彿出現了幻覺一樣。
MySQL事務隔離級別
MySQL預設的事務隔離級別為repeatable read(可重複讀)。
讀未提交
事務的最低隔離級別,在這種隔離級別下,一個事務可以讀取另一個事務未提交的資料。
例子:事務1設定隔離級別為讀未提交,查詢user表資料。
事務2設定隔離級別為讀未提交,修改user表id為1的score。
事務1能夠查詢到事務2修改的資料。
事務2對錶進行了回滾,撤銷修改。
事務1不知道事務2進行了回滾,此時事務1讀到的資料為髒資料。然後事務1對錶資料進行了修改。在事務1看來 score 應該為 60+50=110,但是修改後操作為60,資料不一致。
讀已提交
在一個事務修改資料過程中,如果該事務還沒提交,其他事務不能讀取該資料。
例子:事務2對錶中的資料進行修改,並提交。
事務1對錶的兩次查詢資料不一致,即產生了不可重複讀的問題。
在事務2修改表中資料但又未提交事務時,mysql對該欄位增加了x鎖,事務1不可修改資料。直到事務2提交事務後,事務1才能對該欄位進行修改。
可重複讀
在同一個事務內的查詢都是事務開始時刻一致的。
例子:事務1設定隔離級別為repeatable read,並查詢資料。
事務2設定隔離級別,更改資料並提交。
事務1再次查詢表資料,表資料不變。解決了不可重複讀問題,但不能解決幻讀。
序列化
事務每次讀操作都需要獲得表級共享鎖,讀寫相互都會阻塞。
例子:事務1查詢表資料
事務2對錶資料可讀,但不可讀寫。因此不會出現幻讀的情況。
總結:
- 隔離級別為讀可提交時,寫資料會鎖住相應的行。
- 隔離級別為可重複讀時,如果檢索條件有索引(包括主鍵索引)的時候,預設加鎖方式是next-key 鎖;如果檢索條件沒有索引,更新資料時會鎖住整張表。一個間隙被事務加了鎖,其他事務是不能在這個間隙插入記錄的,這樣可以防止幻讀。
- 隔離級別為序列化時,讀寫資料都會鎖住整張表。
參考資料: