InnoDB多版本控制

概念:

    多版本控制:MVCC,也就是一致性非鎖定讀的具體實現方式。

    具體實現方式爲:如果讀取的行正在執行排他鎖類操作(update、delete等),該查詢則不會等待鎖的釋放,而是讀取該行的一個快照數據。

 

    問題來了,什麼叫做行快照數據呢?

    實際就是當前行數據的歷史版本數據。

 

    下面我們就來通過示例看下MVCC的實現。

 

1.REPEATABLE-READ下的MVCC

    在之前的InnoDB共享鎖和排他鎖示例中,我們可以看到共享鎖與排他鎖是不兼容的,當然我們之前是先執行共享鎖再執行排他鎖示例的,讀者可以試下先執行排他鎖再執行共享鎖。結果也會是一致的。這裏就不再演示。

    我們當前示例與之前有什麼不同呢?

    1)session1(正常查詢)

set autocommit=0;##首先就是關閉自動提交
select * from city where id = 1; ##查詢一行記錄
// res 結果如下,session2中我們要修改其Name
ID	Name	CountryCode	District	Population
1	Kabul	AFG	Kabol	1780000
    
// 查詢完成之後,等待session2的執行    

    2)session2(排他鎖)

set autocommit=0;##首先就是關閉自動提交
update city set name ='KABUL' where id =1; ##修改id=1這條記錄的name

// 這個時候再次執行session1中的查詢,發現name沒有變化,這個是正常的,因爲我們當前事務還沒有提交
select * from information_schema.INNODB_TRX; ##查詢事務信息
// res 可以看到有兩個事務都在運行
trx_id	trx_state	trx_started	trx_requested_lock_id	trx_wait_started	trx_weight	trx_mysql_thread_id	trx_query	trx_operation_state	trx_tables_in_use	trx_tables_locked	trx_lock_structs	trx_lock_memory_bytes	trx_rows_locked	trx_rows_modified	trx_concurrency_tickets	trx_isolation_level	trx_unique_checks	trx_foreign_key_checks	trx_last_foreign_key_error	trx_adaptive_hash_latched	trx_adaptive_hash_timeout	trx_is_read_only	trx_autocommit_non_locking
462617	RUNNING	2019-12-28 18:53:55			3	9			0	1	2	1136	1	1	0	REPEATABLE READ	1	1		0	0	0	0
284711444560536	RUNNING	2019-12-28 18:50:17			0	10			0	0	0	1136	0	0	0	REPEATABLE READ	1	1		0	0	0	0
    
// 執行commit,commit之後再查詢事務就只有一個了
commit;

// 再執行session1中的查詢數據,發現name還是沒有變化,這個時候感覺有點詭異了

    session2中的update事務明明已經提交了,爲什麼session1還是無法讀取到呢。我們再開啓一個session3來看下

 

    3)session3(正常查詢)

select * from city where id = 1;
// res
ID	Name	CountryCode	District	Population
1	KABUL	AFG	Kabol	1780000

// 查詢事務隔離級別
select @@tx_ISOLATION;
// res
@@tx_ISOLATION
REPEATABLE-READ

    發現name值確實變化了。

    有點奇怪了,我們能從這個示例中總結出什麼呢?

    在REPEATABLE-READ隔離級別下的MVCC,select讀取的還是事務開始之前行數據。

    

2.READ-COMMITTED下的MVCC

    我們再來看下如果我們修改了隔離級別,會與之前的有區別嗎

    下面的示例基本與上述一致,主要區別就是要先修改當前會話事務隔離級別

 

    1)session1(正常查詢)

set autocommit=0;##首先就是關閉自動提交
set session tx_isolation ='read-committed';##修改當前session事務隔離級別爲read-committed
select @@tx_ISOLATION;##查詢下是否修改正常

select * from city where id = 1; ##查詢一行記錄
// res 結果如下,session2中我們要修改其Name
ID  Name    CountryCode District    Population
1   KABUL   AFG Kabol   1780000
    
// 查詢完成之後,等待session2的執行    

    2)session2(排他鎖)

set autocommit=0;##首先就是關閉自動提交
set session tx_isolation ='read-committed';##修改當前session事務隔離級別爲read-committed
select @@tx_ISOLATION;##查詢下是否修改正常

update city set name ='kabul' where id =1; ##修改id=1這條記錄的name

// 這個時候再次執行session1中的查詢,發現name沒有變化,這個是正常的,因爲我們當前事務還沒有提交
select * from information_schema.INNODB_TRX; ##查詢事務信息
// res 可以看到有兩個事務都在運行
trx_id	trx_state	trx_started	trx_requested_lock_id	trx_wait_started	trx_weight	trx_mysql_thread_id	trx_query	trx_operation_state	trx_tables_in_use	trx_tables_locked	trx_lock_structs	trx_lock_memory_bytes	trx_rows_locked	trx_rows_modified	trx_concurrency_tickets	trx_isolation_level	trx_unique_checks	trx_foreign_key_checks	trx_last_foreign_key_error	trx_adaptive_hash_latched	trx_adaptive_hash_timeout	trx_is_read_only	trx_autocommit_non_locking
462619	RUNNING	2019-12-28 19:16:27			3	9			0	1	2	1136	1	1	0	READ COMMITTED	1	1		0	0	0	0
284711444560536	RUNNING	2019-12-28 19:15:05			0	10			0	0	0	1136	0	0	0	READ COMMITTED	1	1		0	0	0	0

// 執行commit,commit之後再查詢事務就只有一個了
commit;

// 再執行session1中的查詢數據,發現name已經發生變化了

    我們在session1中再次查詢該數據的時候,發現name已經被修改了。這個與之前1中REPEATABLE-READ中的結果值很不一樣。

    在READ-COMMITTED隔離級別下的MVCC,select讀取的被鎖定行的最新的一份快照數據。
 

    

總結:

    通過上述示例,我們看到了MVCC在不同隔離級別下的讀取方式有所不同,再來總結下:

    在READ-COMMITTED隔離級別下的MVCC,select讀取的被鎖定行的最新的一份快照數據。

    在REPEATABLE-READ隔離級別下的MVCC,select讀取的還是事務開始之前行數據。

 

參考:MySQL技術內幕 InnoDB存儲引擎

 

發佈了124 篇原創文章 · 獲贊 126 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章