天天看點

mysql 你用的什麼隔離級别?并發問題,騰訊面試官讓我回家再看看

作者:夢幻随風的網際網路筆記
mysql 你用的什麼隔離級别?并發問題,騰訊面試官讓我回家再看看

1.面試官考察重點會是?

mysql:存儲引擎、索引,事務

InnoDB是預設的資料庫存儲引擎支援事務。預設的事務隔離級别是 可重複讀,通過MVCC(并發版本控制)來實作。

2.什麼是可重複讀?

repeatable read(mysql的預設隔離級别) 一個事務第一次讀過某條記錄後,另一個事務修改送出了該條記錄後,事務a讀取到的還是第一次的值,這就是可重複讀,同一個事務中多次讀取相同的資料傳回的結果是一樣的。事務不會讀到其他事務對已有資料的修改,即使其他事務已送出,也就是說,事務開始時讀到的已有資料是什麼,在事務送出前的任意時刻,這些資料的值都是一樣的。

3.什麼是幻讀?髒讀?

例如:

第一個事務查詢一個User表id=100發現不存在該資料行,

這時第二個事務又進來了,新增了一條id=100的資料行并且送出了事務。

這時第一個事務新增一條id=100的資料行會報主鍵沖突, 第一個事務再select一下, 發現id=100資料行已經存在,

這就是幻讀。

髒讀 就是一個事務讀到另一個事務沒有送出的資料。事務A修改了一個資料,但未送出,事務B讀到了事務A未送出的更新結果,事務B讀到的就是髒資料。

4.可重複讀會引發幻讀和髒讀嗎?

可重複度 對于其他事務新插入的資料是可以讀到的,這引發了幻讀問題。

其避免了髒讀和不可重複讀問題,但幻讀依然存在。

還是會出現幻讀,(但是mysql解決了幻讀的問題),

通過 undolog版本鍊和 readview實作,其實就是 mvcc

InnoDB實作mvcc 是通過 readview+undolog 來實作

5.MVCC 多版本并發控制(Multi-Version Concurrency Control, MVCC)

不僅僅是解決資料庫的并發問題,很多并發場景都可以使用,他介于使用樂觀鎖和悲觀鎖之間,是一個重要的并發設計方案。

僅在讀送出和可重複讀兩種隔離級别下生效

每行記錄字段都儲存有:

一個最近變更事務Id row trx_id

一個最新删除的事務Id roll_pointer

mysql 你用的什麼隔離級别?并發問題,騰訊面試官讓我回家再看看

6。ReadView包含的内容

  • m_ids 。在生成ReadView時,目前系統中活躍的讀寫事務的事務id清單,即還未送出。
  • min_trx_id 。在生成ReadView時,目前系統中活躍的讀寫事務中最小的事務id;也就是m_ids中 的最小值。
  • max_trx_id 。在生成ReadView時,系統應該配置設定給下一個事務的事務id值。
  • creator_trx_id 。生成該ReadView的事務的事務id。

可重複讀 讀資料的原則 簡單來說 就是:

讀 版本号 小于等于 目前版本的資料( 意思就是讀不到在目前事務之後修改的資料 避免了不可重複讀)            

讀 删除事務版本号 大于 目前版本的資料( 意思就是如果這條資料在之後的事務裡删了,目前事務也能讀)

可重複讀,在第⼀次讀取資料時⽣成⼀個ReadView,隻會在第⼀次執⾏查詢語句時⽣成⼀個 ReadView ,之後的查詢就不會重複⽣成了,是以⼀個事務的查詢結果每次都是⼀樣的。

具體分析是:

如何通過ReadView來判斷記錄的某個版本是可見的?(小于、等于、不在、堅持回溯)

  • 如果trx_id == creator_trx_id,則表明目前事務在通路它自己修改過的記錄,是以該版本可以被目前事務通路。
  • 如果trx_id < min_trx_id,則表明生成該版本的事務在目前事務生成ReadView之前已經送出了,是以該版本可以被目前事務通路。
  • 如果trx_id >= max_trx_id,則表明生成該版本的事務在目前事務生成ReadView之後才開啟,是以該版本不可以被目前事務通路。
  • 如果trx_id in m_ids,說明建立ReadView時生成該版本的事務還是活躍的,該版本不可以被通路。
  • 如果trx_id not in m_ids,說明建立ReadView時生成該版本的事務已經被送出,該版本可以被通路。
  • 如果某個版本的資料對目前事務不可見,那就順着版本鍊找到下一個版本的資料,并繼續執行上面的步驟來判斷記錄的可見性,以此類推,直到版本鍊中的最後一個版本。

在可重讀Repeatable reads事務隔離級别下:

SELECT時,讀取建立版本号<=目前事務版本号,删除版本号為空 或>目前事務版本号。

INSERT時,儲存目前事務版本号為行的建立版本号

DELETE時,儲存目前事務版本号為行的删除版本号

UPDATE時,插入一條新紀錄,儲存目前事務版本号為行建立版本号,同時儲存目前事務版本号到原來删除的行

通過MVCC,雖然每行記錄都要額外的存儲空間來記錄version,需要更多的行檢查工作以及一些額外的維護工作,但可以減少鎖的使用,大多讀操作都不用加鎖,讀取資料操作簡單,性能好。

7.innodb事務日志包括redo log和undo log。

redo log是重做日志,提供前滾操作。(redo log通常是實體日志,記錄的是資料頁的實體修改)

undo log是復原日志,提供復原操作。(undo用來復原行記錄到某個版本。 undo log一般是邏輯日志,根據每行記錄進行記錄。)

undo log不是redo log的逆向過程,其實它們都算是用來恢複的日志。

8.版本鍊

在每次更新該記錄後,都會将舊值放到一條undo日志中。随着更新次數的增多,所有的版本都會被roll_pointer屬性連接配接成一條連結清單,這個連結清單就稱之為版本鍊。

undo log 的復原機制也是依靠這個版本鍊,每次對記錄進⾏改動,都會記錄⼀條undo⽇志,每條undo⽇志也都有⼀個 roll_pointer 屬性(INSERT操作對應的undo⽇志沒有該屬性,因為該記錄并沒有更早的版本),可以将這些undo⽇志都連起來,串成⼀個連結清單

mysql 你用的什麼隔離級别?并發問題,騰訊面試官讓我回家再看看

祝你早日進階,加油!

mysql 你用的什麼隔離級别?并發問題,騰訊面試官讓我回家再看看

繼續閱讀