起因
有一天同事問我,晨哥晨哥,什麼是數據庫的隔離級別,我,額,稍等,冒汗,以前看過,現在忘了。
有時間寫一篇,下次再忘了還能看看。主要是自己看,順便滿足一下自己寫作的慾望,如果你不小心看到了,證明咱倆有緣分,別因爲我寫的不好噴我。
什麼是事務
你以爲第一件事是介紹數據庫隔離級別的定義嗎,
錯,
我們要先了解爲什麼有數據庫的隔離級別。
我們瞭解一件新知識的時候先要明白它是解決什麼問題的,數據庫隔離級別解決的是事務併發的問題。
那麼問題就來了,什麼是事務。
數據庫事務的概念比較簡單,不考試的情況下用口語表達就是幾個事件要麼一起生效,要麼一起失效。
當然這個事件是數據庫的事件,生活中的事兒不要硬往上套。😄,笑臉,手動滑稽。
不鬧了,說正經的。正經臉。
併發事務的問題
事務併發會出現什麼問題,這還不簡單,兩個覆蓋問題,三個查詢問題。
這就有意思了,什麼叫兩個覆蓋,三個查詢。
咱們以最經典的銀行卡餘額爲例。 假設有一張表,裏面就一個字段 money , 咱來看一下併發事務的問題。
money |
---|
1000 |
第一種覆蓋,因爲回滾覆蓋
時間點 | 事務A | 事務B |
---|---|---|
T1 | 開啓事務 | 開啓事務 |
T2 | 讀到 1000 | 讀到 1000 |
T3 | 給賬號 + 500 | |
T4 | 賬號餘額 1500 | |
T5 | 提交事務 | |
T6 | 給賬號 -500 | |
T7 | 賬號餘額 500 | |
T8 | 回滾事務 | |
T9 | 賬號變 1000 |
最後丟失了事務 B 提交的記錄。
第二種覆蓋,因爲提交覆蓋
時間點 | 事務A | 事務B |
---|---|---|
T1 | 開啓事務 | 開啓事務 |
T2 | 讀到 1000 | 讀到 1000 |
T3 | 給賬號 + 500 | |
T4 | 賬號餘額 1500 | |
T5 | 提交事務 | |
T6 | 給賬號 -500 | |
T7 | 賬號餘額 500 | |
T8 | 提交事務 | |
T9 | 賬號變 500 |
這是因爲提交覆蓋了 B 提交的事務。
第一種查詢,查詢到未提交的數據
時間點 | 事務A | 事務B |
---|---|---|
T1 | 開啓事務 | 開啓事務 |
T2 | 讀到 1000 | |
T3 | 給賬號 + 500 | |
T4 | 賬號餘額 1500 | |
T5 | 查詢到賬戶餘額 1500(髒讀) | |
T6 | 再給賬戶 +100 | 回滾事務 |
T7 | 賬號餘額 1600 | |
T8 | 提交事務 | |
T9 | 賬號變 1600 |
因此,讀到未提交的數據,也叫髒讀。
第二種查詢,查詢到已提交的數據
時間點 | 事務A | 事務B |
---|---|---|
T1 | 開啓事務 | 開啓事務 |
T2 | 讀到 1000 | 讀到 1000 |
T3 | 給賬號 + 500 | |
T4 | 賬號餘額 1500 | |
T5 | 提交事務 | |
T6 | 又讀一次,變 1500 了 | |
T7 | 讀兩次效果不一樣 |
這種讀兩次效果不一樣的,也叫不可重複讀。
第三種查詢,查詢到新插入的數據
時間點 | 事務A | 事務B |
---|---|---|
T1 | 開啓事務 | 開啓事務 |
T2 | sum() 一下值是 1000 | |
T3 | 插入一條新的 1000 的記錄 | |
T4 | 提交事務 | |
T5 | 再 sum() 一下值變成 2000 了 |
這種奇幻的效果就叫做幻讀。
數據庫隔離級別
既然事務併發會有這麼多的問題,那我們設計系統的時候總得有所取捨,到底哪些現象是和合理的,哪些現象是不合理的要避免的。
數據庫設計也是一樣,這些問題有些是不合理一定要避免的,有些呢,在業務場景中是合理的,不能一棍子打死。
那到底哪些場景下是合理的哪些是不合理的,數據庫把它設計成了一個可選項,就叫數據庫隔離級別,供開發人員選擇。
serializable (串行,建議記英文,中文表達不好)
所有事務操作都是串行的,一個事務執行完才執行下一下,這樣肯定不會用問題,當然效率也是最慢。
repeatable read (可重複讀)
就是讀不到別的事務的對記錄的更新【包括已提交和未提交】,能讀到已經提交的插入。InnoDB 存儲引擎通過多版本併發控制,MVCC 解決了幻讀的問題。
read committed (讀已提交)
就是能讀到別的事務對記錄的更新,也能讀到已插入的記錄
read uncommited (讀未提交)(也叫髒讀)
可以看到其他事務未提交的更新,插入也能看到。