事務的四大ACID 屬性:Atomicity 原子性、Consistency 一致性、Isolation 隔離性、Durability 永續性。
原子性: 事務是最小的執行單位不可分割,強調事務的不可分割
一致性: 事務執行前後,資料的完整性保持一致。
永續性: 一旦事務執行結束,資料就儲存到資料庫。
隔離性: 一個事務執行的前後不應該受到其他事務的干擾。
MySQL的事務隔離級別有四種:未提交讀、已提交讀、可重複讀和序列化。
未提交讀: 事務A可以讀取到事務B還未提交的資料。比如事務B將小明的賬戶餘額從100改到110,事務B還沒提交,在這個隔離級別下事務A就讀取到的資料就是110。如果說事務B回滾了,那資料庫裡小明的賬戶餘額又變成100了,可是事務A返回的資料卻是110。這就造成了髒讀。
已提交讀: 事務A讀取到資料是事務B提交後的資料,即一個事務提交後,其變更才會被另一個事務讀取到。比如事務B將小明的賬戶餘額從100改到110,事務B還沒提交的時候,事務A讀取到的資料仍然是100。因為在這個隔離級別下一個事務只能讀取到另一個事務修改後且提交事務後的資料。但是這種情況會造成一個問題就是,事務A在事務B隱式提交資料後讀取到的資料是110,這是沒問題的,但是在事務A還沒提交前,事務B又將小明的賬戶餘額改為120並隱式提交,然後事務A再來讀取的時候就讀到了120,所以事務A的兩次讀取結果不一致。這就造成了不可重複讀。
可重複讀: 事務A只能讀到事務B修改的已提交了事務的資料,但是第一次讀取的資料,即使別的事務修改了這個值,這個事務再讀取這條資料的時候還是和第一次獲取的一樣,不會隨著別的事務的修改而改變。這和已提交讀的區別就在於,它重複讀取的值是不變的。所以叫可重複讀,很貼切的名字。拿剛才的例子就是,事務A在自己的事務裡多次讀取小明的賬戶餘額時,如果第一次讀取的是100,那麼不管在這之後事務B對它進行如何的修改,對於事務A來說多次讀取的結果都是100。可重複讀解決了不可重複讀(聽起來像是廢話),但是存在幻讀的情況。
幻讀:當事務A查詢賬戶餘額=100的客戶個數時,假如返回的是1萬,這時事務B將小明的賬戶餘額由110改為100並提交事務,事務A再次查詢賬戶餘額=100的客戶個數時返回的統計個數變成了1萬零1。這就是幻讀。
幻讀和不可重複讀有區別。不可重複讀側重點在於讀取同一條資料,資料被修改,如讀小明的賬戶餘額;幻讀的側重點在於新增或者刪除 (資料條數變化),同樣的條件兩次查詢記錄數不一樣。
序列化: 上面三個隔離級別對同一條記錄的讀和寫都可以併發進行,但是序列化的隔離級別下就只能進行讀-讀併發。只要有一個事務操作一條記錄的寫,那麼其他事務要讀這條記錄的事務都得等著。例如,事務B修改小明的賬戶還未提交前事務A來讀,那麼事務A就只能等著事務B提交之後才能讀。
序列化的隔離級別一半沒人用,因為效能比較低,常用的是已提交讀和可重複讀。
大多數資料庫採用已提交讀,MySQ的預設隔離級別是:可重複讀。可以通過 select @@global.tx_isolation;來檢視當前隔離級別。
✘不會造成 , ✔可能造成
事務隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
未提交度 | ✔ | ✔ | ✔ |
已提交讀 | ✘ | ✔ | ✔ |
可重複讀 | ✘ | ✘ | ✔ |
序列化 | ✘ | ✘ | ✘ |