mvcc即多版本併發控制,通過讀取指定版本的歷史記錄,並通過一些手段保證讀取的記錄值符合事務所處的隔離級別,在不加鎖的情況下解決讀寫衝突
如果小夥伴對mvcc不熟,估計看了這句話會有點懵,沒事,等看完這篇文章你就能看懂這句話了
對於使用innodb儲存引擎的表來說,聚集索引記錄中都包含下面2個必要的隱藏列
trx_id:乙個事務每次對某條聚集索引記錄進行改動時,都會把該事務的事務id賦值給trx_id隱藏列
roll_pointer:每次對某條聚集索引記錄進行改動時,都會把舊的版本寫入undo日誌中。這個隱藏列就相當於乙個指標,通過他找到該記錄修改前的資訊
如果乙個記錄的name從貂蟬被依次改為王昭君,西施,會有如下的記錄,多個記錄構成了乙個版本鏈
先回顧一下隔離級別的概念,這樣看後面的內容不至於發懵
√ 為會發生,×為不會發生
建立如下表
create table `account` (
`id` int(2) not null auto_increment,
`name` varchar(10) default null,
`balance` int(3) default '0',
primary key (`id`)
) engine=innodb auto_increment=4 default charset=utf8mb4;
表中的資料如下,設定隔離級別為讀已提交
不可重複讀是指在事務1內,讀取了乙個資料,事務1還沒有結束時,事務2也訪問了這個資料,修改了這個資料,並提交。緊接著,事務1又讀這個資料。由於事務2的修改,那麼事務1兩次讀到的的資料可能是不一樣的,因此稱為是不可重複讀。表中的資料如下,設定隔離級別為可重複讀
仔細看這個例子和上面的例子在t3時間段的輸出,理解了什麼叫可重複讀了吧?當我們將當前會話的隔離級別設定為可重複讀的時候,當前會話可以重複讀,就是每次讀取的結果集都相同,而不管其他事務有沒有提交。
我當初做完這個實驗的時候,我都蒙蔽了,mysql是如何支援這兩種隔離級別的?我們接著往下看
為了判斷版本鏈中哪個版本對當前事務是可見的,mysql設計出了readview的概念。4個重要的內容如下
m_ids:在生成readview時,當前系統中活躍的事務id列表min_trx_id:在生成readview時,當前系統中活躍的最小的事務id,也就是m_ids中的最小值max_trx_id:在生成readview時,系統應該分配給下乙個事務的事務id值creator_trx_id:生成該readview的事務的事務id
當對表中的記錄進行改動時,執行insert,delete,update這些語句時,才會為事務分配唯一的事務id,否則乙個事務的事務id值預設為0。
max_trx_id並不是m_ids中的最大值,事務id是遞增分配的。比如現在有事務id為1,2,3這三個事務,之後事務id為3的事務提交了,當有乙個新的事務生成readview時,m_ids的值就包括1和2,min_trx_id的值就是1,max_trx_id的值就是4
mvcc判斷版本鏈中哪個版本對當前事務是可見的過程如下
執行過程如下:
如果被訪問版本的trx_id=creator_id,意味著當前事務在訪問它自己修改過的記錄,所以該版本可以被當前事務訪問
如果被訪問版本的trx_id被訪問版本的trx_id>=max_trx_id,表明生成該版本的事務在當前事務生成readview後才開啟,該版本不可以被當前事務訪問
被訪問版本的trx_id是否在m_ids列表中
4.1 是,建立readview時,該版本還是活躍的,該版本不可以被訪問。順著版本鏈找下乙個版本的資料,繼續執行上面的步驟判斷可見性,如果最後乙個版本還不可見,意味著記錄對當前事務完全不可見
4.2 否,建立readview時,生成該版本的事務已經被提交,該版本可以被訪問
看著圖有點懵?是時候來個例子了
建立如下表
create table `girl` (
`id` int(11) not null,
`name` varchar(255),
`age` int(11),
primary key (`id`)
) engine=innodb default charset=utf8;
read committed(讀已提交),每次讀取資料前都生成乙個readview下面是3個事務執行的過程,一行代表乙個時間點
先分析一下5這個時間點select的執行過程
系統中有兩個事務id分別為100,200的事務正在執行
執行select語句時生成乙個readview,mids=[100,200],min_trx_id=100,max_trx_id=201,creator_trx_id=0(select這個事務沒有執行更改操作,事務id預設為0)
最新版本的name列為西施,該版本trx_id值為100,在mids列表中,不符合可見性要求,根據roll_pointer跳到下乙個版本
下乙個版本的name列王昭君,該版本的trx_id值為100,也在mids列表內,因此也不符合要求,繼續跳到下乙個版本
下乙個版本的name列為貂蟬,該版本的trx_id值為10,小於min_trx_id,因此最後返回的name值為貂蟬
再分析一下8這個時間點select的執行過程
系統中有乙個事務id為200的事務正在執行(事務id為100的事務已經提交)
執行select語句時生成乙個readview,mids=[200],min_trx_id=200,max_trx_id=201,creator_trx_id=0
最新版本的name列為楊玉環,該版本trx_id值為200,在mids列表中,不符合可見性要求,根據roll_pointer跳到下乙個版本
下乙個版本的name列為西施,該版本的trx_id值為100,小於min_trx_id,因此最後返回的name值為西施
當事務id為200的事務提交時,查詢得到的name列為楊玉環。
repeatable read(可重複讀),在第一次讀取資料時生成乙個readview
可重複讀因為只在第一次讀取資料的時候生成readview,所以每次讀到的是相同的版本,即name值一直為貂蟬,具體的過程上面已經演示了兩遍了,我這裡就不重複演示了,相信你一定會自己分析了。
如何當好面試官
今年面試的人比較多,加起來快一百人了。由於面試任務比較多,也有越來越多的小夥伴加入了面試官的行列。總結一些面試相關的方 希望新晉面試官有些幫助,最終能高效面試。面試官的目標是為組織找到合適的人,一切行為都是圍繞這個主體來運作的。我們現在的面試還是類似於考試,這是一種能夠在短時間內高效選擇到合格面試者...
測試面試,面試官問如何測試電梯
面試官問你 怎麼測試電梯 回答思路 以電梯為例 1 那麼首先,你要反問面試官,需求是什麼樣的,比如測什麼樣的電梯,是普通電梯,觀光電梯,還是其他 2 如果回答沒有,那麼你的思路應該就是 沒有需求文件,但我了解電梯的基本業務功能,以此依據,從下面幾個方面進行分析 功能測試 單個功能,邏輯業務 功能互動...
面試官 如何控制多執行緒執行順序?
先看如下 public class test static thread thread2 newthread static thread thread3 newthread public static void main string args throws interruptedexception...