RR與RC隔離級(jí)別下索引和鎖的測(cè)試腳本示例代碼
基本概念
當(dāng)前讀與快照讀
在MVCC中,讀操作可以分成兩類:快照讀 (snapshot read)與當(dāng)前讀 (current read)。 快照讀,讀取的是記錄的可見版本 (有可能是歷史版本),不用加鎖。當(dāng)前讀,讀取的是記錄的最新版本,并且對(duì)返回的記錄,都會(huì)加上鎖,保證在事務(wù)結(jié)束前,這條數(shù)據(jù)都是最新版本。
快照讀:簡(jiǎn)單的select操作,屬于快照讀,不加鎖(Serializable除外)。
select * from table where ?;
當(dāng)前讀:特殊的讀操作,插入/更新/刪除操作,屬于當(dāng)前讀,需要加鎖?!?br />
select * from table where ? lock in share mode; select * from table where ? for update; insert into table values (); update table set ? where ?; delete from table where ?;
隔離級(jí)別與加鎖機(jī)制
- Read Uncommitted 會(huì)發(fā)生臟讀,不考慮。
- Read Committed (RC) 針對(duì)當(dāng)前讀,RC隔離級(jí)別保證對(duì)讀取到的記錄加鎖 (Gap Locking),存在幻讀現(xiàn)象。
- Repeatable Read (RR) 針對(duì)當(dāng)前讀,RR隔離級(jí)別保證對(duì)讀取到的記錄加鎖 (Record Locking),同時(shí)保證對(duì)讀取的范圍加鎖,新的滿足查詢條件的記錄不能夠插入 (Gap Locking),不存在幻讀現(xiàn)象。
- Serializable 所有的讀操作均為退化為當(dāng)前讀,讀寫沖突,因此并發(fā)度急劇下降,不考慮。
測(cè)試腳本
-- 基本操作 -- -- 查詢事務(wù)隔離級(jí)別,默認(rèn)是RR show variables like '%isolation%'; -- 設(shè)置事務(wù)隔離級(jí)別為RC set session transaction isolation level read committed; -- 數(shù)據(jù)初始化 -- begin; drop table if exists user; CREATE TABLE `user` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `email` varchar(64) NOT NULL, `age` int(11) NOT NULL, `address` varchar(64) NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `uniq_email` (`email`), KEY `idx_age` (`age`) ); insert into user (email, age, address) values ("test1@elsef.com", 18, "address1"); insert into user (email, age, address) values ("test2@elsef.com", 20, "address2"); insert into user (email, age, address) values ("test3@elsef.com", 20, "address3"); commit; select * from user; -- 一、trx_id示例 begin; SELECT TRX_ID FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID(); select * from user; SELECT TRX_ID FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID(); SHOW ENGINE INNODB STATUS; update user set age = 22 where id = 3; -- 查詢事務(wù)id SELECT TRX_ID FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_MYSQL_THREAD_ID = CONNECTION_ID(); -- INNODB 引擎狀態(tài) SHOW ENGINE INNODB STATUS; commit; -- 二、可重復(fù)讀、不可重復(fù)讀示例 -- session1 set session transaction isolation level read committed; begin; -- session2 set session transaction isolation level repeatable read; begin; -- session1 select * from user; -- session2 select * from user; -- session3 begin; insert into user (email, age, address) values ("test4@elsef.com", 30, "address4"); commit; -- session1 這里因?yàn)槭荝C,所以可以讀到trx3提交的新數(shù)據(jù),這里如果是證明不可重復(fù)讀的話應(yīng)該使用update而不是insert select * from user; commit; -- session2 這里因?yàn)槭荝R,所以不會(huì)讀到trx3提交的新數(shù)據(jù) select * from user; commit; -- 三、快照讀幻讀示例 -- session1 set session transaction isolation level repeatable read; begin; -- 這里使用快照讀 select * from user; -- session2 begin; insert into user (email, age, address) values ("test4@elsef.com", 30, "address4"); commit; select * from user; -- session1 select * from user; -- 這里讀不到test4@的數(shù)據(jù),因?yàn)槭荝R -- 這里發(fā)生了幻讀 insert into user (email, age, address) values ("test4@elsef.com", 30, "address4"); -- 插入失敗因?yàn)閑mail唯一索引沖突 commit; -- 四、當(dāng)前讀幻讀示例 -- RC -- session1 set session transaction isolation level read committed; begin; -- 這里會(huì)對(duì)所有滿足條件的age=20的記錄加鎖,因?yàn)槭荝C,所以沒有GAP鎖 delete from user where age = 20; select * from user; -- session2 set session transaction isolation level read committed; begin; -- 因?yàn)閠rx1沒有加GAP鎖,所以之類可以插入age=20的記錄 insert into user (email, age, address) values ("test4@elsef.com", 20, "address4"); select * from user; -- 可以查到4條數(shù)據(jù),可以讀到trx1的刪除數(shù)據(jù),因?yàn)槭荝C,trx1未提交所以沒影響trx2 commit; -- session1 select * from user; -- 可以讀到trx2新插入的數(shù)據(jù),雖然trx1是當(dāng)前讀,但是并未添加相應(yīng)的next-key鎖,沒有阻止trx2的新數(shù)據(jù)插入 commit; --RR -- session1 set session transaction isolation level repeatable read; begin; delete from user where age = 20; select * from user; -- session2 begin; -- 這里會(huì)阻塞,因?yàn)閠rx1在age=20周圍加了GAP鎖 -- 非唯一索引,首先,通過索引定位到第一條滿足查詢條件的記錄,加記錄上的X鎖,加GAP上的GAP鎖,然后加主鍵聚簇索引上的記錄X鎖; -- 然后讀取下一條,重復(fù)進(jìn)行。直至進(jìn)行到第一條不滿足條件的記錄,此時(shí),不需要加記錄X鎖,但是仍舊需要加GAP鎖,最后返回結(jié)束。 insert into user (email, age, address) values ("test4@elsef.com", 20, "address4"); -- 直到超時(shí),ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction -- 此時(shí)如果查詢可以看到3條記錄 commit; -- session1 -- 此時(shí)只能看到1條記錄,另外兩條被刪除了 select * from user; commit; -- 唯一索引+RC -- session1 set session transaction isolation level read committed; begin; delete from user where email = "test3@elsef.com"; -- session2 begin; -- 可以讀到,因?yàn)閠rx1是RC select * from user where email = "test3@elsef.com"; -- 嘗試更新這個(gè)記錄的age,會(huì)阻塞直到超時(shí),因?yàn)閑mail是唯一索引已經(jīng)被trx1鎖住了,同時(shí)也會(huì)在對(duì)應(yīng)的主鍵索引上加鎖 -- 注意這里操作的id=3就是trx1中操作的email的同一行記錄 update user set age = 40 where id = 3; -- session1 commit; -- session2 commit; -- 無(wú)索引+RC -- session1 set session transaction isolation level read committed; begin; -- 由于address字段無(wú)索引,所以Innodb會(huì)對(duì)所有行進(jìn)行加鎖,由MySQL server進(jìn)行判斷并釋放鎖 delete from user where address = "address3"; -- session2 set session transaction isolation level read committed; begin; -- 這一行會(huì)成功,因?yàn)檫@一行沒有加鎖(先加了后釋放了) update user set age = 10 where address = "address2"; -- 這一行同樣會(huì)被阻塞,原因是它已經(jīng)被trx1的語(yǔ)句加了鎖了,全部符合條件的都加鎖了 update user set age = 10 where address = "address3"; -- session1 commit; -- session2 commit; -- 非唯一索引+RR -- session1 set session transaction isolation level repeatable read; begin; delete from user where age = 20; -- session2 set session transaction isolation level repeatable read; begin; -- 這里會(huì)阻塞,因?yàn)閠rx1中已經(jīng)鎖住了age=20的記錄以及加上了GAP鎖,所以這里18已經(jīng)落入鎖區(qū)間 insert into user (email, age, address) values ("test4@elsef.com", 18, "address4"); -- session1 commit; -- session2 commit; -- 無(wú)索引RR -- session1 set session transaction isolation level repeatable read; begin; -- 沒有索引,那么會(huì)鎖上表中的所有記錄,同時(shí)會(huì)鎖上主鍵索引上的所有GAP,杜絕所有的并發(fā)更新操作 delete from user where address = "address3"; -- session2 set session transaction isolation level repeatable read; begin; -- 這里會(huì)阻塞,原因是主鍵已經(jīng)被加上了GAP鎖,所以新的插入不能執(zhí)行成功 insert into user (email, age, address) values ("test4@elsef.com", 18, "address4"); -- session1 commit; -- session2 commit; -- 死鎖 簡(jiǎn)單示例 -- session1 begin; delete from user where id = 1; -- session2 begin; delete from user where id = 3; -- session1 delete from user where id = 3; -- seession2 -- 這里MySQL判斷發(fā)生了死鎖,中斷了一個(gè)trx -- ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction delete from user where id = 1; -- session1 rollback; -- session2; rollback; -- 五、死鎖 insert示例 drop table if exists t1; begin; create table t1 ( `id` bigint not null auto_increment, primary key (`id`) ); insert into t1 values(1); insert into t1 values(5); commit; select * from t1; -- session1 begin; insert into t1 values (2); -- sessioin2 begin; -- 這里會(huì)阻塞 insert into t1 values (2); -- session3 begin; -- 這里會(huì)阻塞 insert into t1 values (2); -- session1; -- 此時(shí)回滾,trx2和trx3收到通知,MySQL自動(dòng)中斷一個(gè)trx,因?yàn)榘l(fā)生了死鎖 -- ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction rollback; --session2; rollback; --session3; rollback;
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
mysql查詢字符串替換語(yǔ)句小結(jié)(數(shù)據(jù)庫(kù)字符串替換)
有時(shí)候我們需要對(duì)mysql的字符串進(jìn)行替換,我們就可以通過sql語(yǔ)句直接實(shí)現(xiàn)了,不過對(duì)于大數(shù)據(jù)量的字段不建議使用此方法2012-07-07mysql出現(xiàn)ERROR 1819 (HY000)的解決方法
這篇文章主要為大家詳細(xì)介紹了mysql出現(xiàn)ERROR 1819 (HY000)的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-10-10Mysql存儲(chǔ)引擎InnoDB和Myisam的六大區(qū)別
這篇文章主要介紹了Mysql存儲(chǔ)引擎InnoDB和Myisam的六大區(qū)別,本文從構(gòu)成上、事務(wù)處理、SQL操作、自動(dòng)ID、表行數(shù)等方面講解了它的區(qū)別,需要的朋友可以參考下2015-02-02MYSQL必知必會(huì)讀書筆記第六章之過濾數(shù)據(jù)
本文給大家分享MYSQL必知必會(huì)讀書筆記第六章之過濾數(shù)據(jù)的相關(guān)知識(shí),非常實(shí)用,特此分享到腳本之家平臺(tái),供大家參考2016-05-05mysql 5.6 從陌生到熟練之_數(shù)據(jù)庫(kù)備份恢復(fù)的實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇mysql 5.6 從陌生到熟練之_數(shù)據(jù)庫(kù)備份恢復(fù)的實(shí)現(xiàn)方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來(lái)看看吧2016-10-10MySQL兩個(gè)查詢?nèi)绾魏喜⒊梢粋€(gè)結(jié)果詳解
利用union關(guān)鍵字,可以給出多條select語(yǔ)句,并將它們的結(jié)果組合成單個(gè)結(jié)果集,下面這篇文章主要給大家介紹了關(guān)于MySQL兩個(gè)查詢?nèi)绾魏喜⒊梢粋€(gè)結(jié)果的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08