1. 程式人生 > >MySQL技術內幕 InnoDB儲存引擎:一致性非鎖定讀

MySQL技術內幕 InnoDB儲存引擎:一致性非鎖定讀

一致性的非鎖定行讀(consistent nonlocking read)是指InnoDB儲存引擎通過行多版本控制(multi versioning)的方式來讀取當前執行時間資料庫中行的資料。如果讀取的行正在執行DELETE、UPDATE操作,這是讀取操作不會因此而會等待行上鎖的釋放,相反,InnoDB會去讀取行的一個快照資料。

下圖直觀展示了一致性的非鎖定行讀:
在這裡插入圖片描述

之所以稱其為非鎖定讀,因為不需要等待訪問的行上X鎖的釋放。快照資料是指該行的之前版本的資料,該實現是通過undo段來完成。而undo段用來在此事務中回滾資料,因此快照資料本身是沒有額外的開銷。此外,讀取快照資料是不需要上鎖的,因為沒有事務需要對歷史的資料進行修改操作。

可以看到,非鎖定讀機制極大地提髙了資料庫的併發性。在InnoDB儲存引擎的預設設定下,這是預設的讀取方式,即讀取不會佔用和等待表上的鎖。但是在不同事務隔離級別下,讀取的方式不同,並不是在每個事務隔離級別下都是採用非鎖定的一致性讀。此外,即使都是使用非鎖定的一致性讀,但是對於快照資料的定義也各不相同。

通過圖6-4可以知道,快照資料其實就是當前行資料之前的歷史版本,每行記錄可能有多個版本。就圖6-4所顯示的,一個行記錄可能有不止一個快照資料,一般稱這種技術為行多版本技術。由此帶來的併發控制,稱之為多版本併發控制(MultiVersionConcurrencyControl*MVCC)

在事務隔離級別READ COMMITTED和REPEATABLE READ(InnoDB儲存引擎的預設事務隔離級別)下,InnoDB儲存引擎使用非鎖定的一致性讀。然而,對於快照資料的定義卻不相同。在READ COMMITTED事務隔離級別下,對於快照資料,非一致性讀總是讀取被鎖定行的最新一份快照資料。而在REPEATABLE READ事務隔離級別下,對於快照資料,非一致性讀總是讀取事務開始時的行資料版本。來看下面的一個例子,首先在當前MySQL資料庫的連線會話A中執行如下SQL語句:

在這裡插入圖片描述

會話A中已通過顯式地執行命令BEGIN開啟了一個事務,並讀取了表parent中id為.的資料,但是事務並沒有結束。與此同時,使用者再開啟另一個會話B,這樣可以模擬併發的情況,然後對會話B做如下的操作:
在這裡插入圖片描述
在會話B中將事務表parent中id為1的記錄修改為id=3,但是事務同樣沒有提交, 這樣id=l的行其實加了一個X鎖。這時如果在會話A中再次讀取id為1的記錄,根據InnoDB儲存引擎的特性,即在READ COMMITTED和REPEATETABLE READ的事務隔離級別下會使用非鎖定的一致性讀。回到之前的會話A,接著上次未提交的事務,執行SQL語句SELECT * FROM parent WHERE id=l的操作,這時不管使用READ COMMITTED還是REPEATABLE READ的事務隔離級別,顯示的資料應該都是:
在這裡插入圖片描述

由於當前id=l的資料被修改了1次,因此只有一個行版本的記錄。接著,在會話B中提交上次的事務。
在這裡插入圖片描述

在會話B提交事務後,這時在會話A中再執行SELECT * FROM parent WHERE id=l的SQL語句,在READ COMMITTED和REPEATABLE事務隔離級別下得到結果 就不一樣了。對於READ COMMITTED的事務隔離級別,它總是讀取行的最新版本,如果行被鎖定了,則讀取該行版本的最新一個快照(fresh snapshot)。在上述例子中,因為會話B已經提交了事務,所以READ COMMITTED事務隔離級別下會得到如下結果:
在這裡插入圖片描述

而對於REPEATETABLE 的事務隔離級別,總是讀取事務開始時的行資料。因此對於REPEATETABLE READ事務隔離級別,其得到的結果如下:
在這裡插入圖片描述

下面將從時間的角度展現上述演示的示例過程,如表 6- 8 所示。需要特別注意的是,對於 READ COMMITTED 的事務隔離級別而言,從資料庫理論的角度來看,其違反了事務 ACID 中的 l 的特性,即隔離性。
在這裡插入圖片描述

本文整理自:《MySQL技術內幕 InnoDB儲存引擎

個人微信公眾號:
這裡寫圖片描述

作者:jiankunking 出處:http://blog.csdn.net/jiankunking