Mysql筆記:事務隔離級別理解

這個問題其實有不少人都已經教科書式的總結了不少遍,如:面試

隔離級別中文描述此級別問題(面試官喜歡用這個)READ UNCOMMITED未提交讀髒讀READ COMMITED提交讀不可重複讀REPEATABLE READ可重複讀幻讀SERIALIZABLE串行化鎖sql

可是在這個表格中最後一列的問題因何產生,不少人會不明白其中的原因。我先說下個人理解,而後再來一點點解釋:併發

事務隔離的四個級別能夠先用「事務是否可併發」來劃分紅兩個對立面來理解:性能

  1. 事務不可併發在 Mysql 中只有 SERIALIZABLE 這一級別知足;其它的固然是事務可併發了;
  2. 事務不可併發,Mysql 選擇了串行化這一實現方式,所以引入了鎖,也帶來了性能問題;
  3. 事務可併發,所以在多個併發的事務期間,咱們並不知道哪一個事務的哪段邏輯(begin/rollback/commit)會在下一個時間片內被執行;

併發事務帶來的問題事務

在上面的描述中,二、3是對1的一個擴展,2不難理解,可是 3 可能有些生硬,咱們能夠簡單的換種理解方式,it

  1. 假設同一時間有兩個事務: A & B ,而且事務 A 執行 update,事務 B 執行 select。
  2. 假設事務的開啓、提交、回滾及事務中執行的 Action 都能在一個 cpu 時間片內完成,那麼可把 A&B 的事務拆成以下邏輯調用段:

#事務A事務B1beginbegin2updateselect3commitcommit4rollbackrollbackio

基於上面的假設,咱們再來理解事務併發狀況下各類問題的產生:擴展

髒讀date

  1. A begin => update 後讓 cpu
  2. 同時B begin => select,可是事務 B 很心大,並無去驗證 A 的有效性,讀到了 A update 後的數據;
  3. A 在下一個 cpu 時間又獲得了調度,A 發現本身剛纔的操做無效了,A rollback 獲得了執行,可是它沒法告知 B 了,因此 B 讀到的數據是無效的;
  4. 不可重複讀
  5. 知道了髒讀的緣由後,爲了解決這個問題,Mysql 規定 B 讀的數據只能讀取已經 commit 狀態的數據:
  6. A begin => update 後讓 cpu
  7. 同時 B begin => select,此次 B 很當心地驗證 A 的數據是否 commit 了,B 此次讀到了 A begin 之前的數據;
  8. 事務 A 在下一個 cpu 時間又獲得了調度,A commit 了;
  9. B 再次 select,可是已經 select 到了 A commit 後的數據了,B 在 A commit 先後讀到了兩次不同的數據,即不可重複讀了;
  10. 幻讀
  11. 知道了不可重複讀的緣由後,Mysql 又規定,既然 B 第一次讀到的是 A commit 前的數據,那麼在事務 B 中後面不管多少次 select 都只能讀到 A commit 以前的數據。可是問題又來了:
  12. 此次 A 不是 update 了,而是 insert,B select 也不是單條了,而是 select range;
  13. B 在 A commit 先後兩次 select range 會發現結果的數量不一至;這就是幻讀;
  14. InnoDB 針對幻讀也作了處理:MVCC,在每一行後都有隱藏的兩列版本號來實現;大體與處理不可重複讀相同;
相關文章
相關標籤/搜索