Mysql中的Innodb事務(wù)和鎖詳解
Innodb事務(wù)和鎖
一. 事務(wù)隔離級(jí)別
- READ UNCOMMITED :讀未提交,事務(wù)之間可以看到彼此之間正在修改的內(nèi)容,會(huì)出現(xiàn)所謂的臟讀現(xiàn)象
- READ COMMITED : 讀已提交,只能讀取已經(jīng)提交的事務(wù)修改的數(shù)據(jù),不會(huì)出現(xiàn)臟讀的現(xiàn)象,但會(huì)出現(xiàn)不可重復(fù)讀和幻讀的情況
- REPEATABLE READ : 可重復(fù)度,在innodb中解決了不可重復(fù)讀和幻讀的問(wèn)題
- SERIALIZED : 串行化, 這個(gè)使用的比較少,隔離性最強(qiáng),性能也最差
二. 鎖類型
- S LOCK : 共享鎖 : S鎖與S鎖相互兼容,與X鎖不兼容
- X LOCK :排他鎖 :與其他所有鎖類型不兼容,簡(jiǎn)單的可以理解為讀寫(xiě)鎖即可
- 意向鎖 (IS, IX) : 主要是用來(lái)表達(dá)加鎖的一種層次概念,比如希望在行級(jí)別加X(jué)鎖,那么就需要在表級(jí)和頁(yè)級(jí)別加上IX鎖,意向鎖整體上兼容性會(huì)比較好,如果當(dāng)前表中已經(jīng)有了多個(gè)行級(jí)鎖,如果希望嘗試加表鎖,如果沒(méi)有意向鎖的話,那么就需要取檢測(cè)當(dāng)前行鎖的加鎖情況,但是有了意向鎖,就可以快速判斷當(dāng)前嘗試加表鎖可能是需要等待的。
監(jiān)控方法
- SHOW ENGINE INNODB STATUS 命令查看innodb引擎信息,其中包含當(dāng)前執(zhí)行事務(wù)的狀態(tài)和鎖的狀態(tài)
- 通過(guò)information_schema提供的表來(lái)排查可能存在的問(wèn)題
- a. information_schema.innodb_trx
- b. information_schema.innodb_locks
- c. innodb_lock_waits
三.鎖釋放的時(shí)機(jī)
lock通常在事務(wù)commit或是rollback之后才會(huì)釋放
四. 一致性非鎖定讀
這是非常常見(jiàn)的問(wèn)題,事務(wù)中會(huì)有大量的select操作,select操作通常情況下是不會(huì)對(duì)數(shù)據(jù)做加鎖操作的, 這樣保證了數(shù)據(jù)的并發(fā)性能,在不同的事務(wù)隔離級(jí)別下,非一致性鎖定讀的行為是不太一樣的
- READ COMMITED : 讀取undo_log中該行最新的一條快照數(shù)據(jù)
- READ REPETABLE : 讀取undo_log中,最近的早于當(dāng)前事務(wù)開(kāi)啟時(shí)間的快照數(shù)據(jù)
五. 加鎖算法
上文描述了鎖的類型,即排它鎖,共享鎖,意向鎖之類,這里所說(shuō)的是加鎖的算法,即為innodb使用了什么樣的加鎖策略來(lái)處理實(shí)際場(chǎng)景中的并發(fā)問(wèn)題。
- record lock : 行鎖,對(duì)單個(gè)行記錄進(jìn)行加鎖,行是innodb的最小數(shù)據(jù)管理單位,innodb中有專門(mén)的數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)和管理行記錄,我們所有的查詢的數(shù)據(jù)最終都會(huì)落到存儲(chǔ)引擎的行上
- gap lock : 間隙鎖,即對(duì)間隙加鎖,間隙其實(shí)就這里只是針對(duì)間隙,不包括行(todo ,間隙的概念需要搞一下)
- next-key lock : 對(duì)行和間隙和行都進(jìn)行加鎖
netx-key lock算法主要解決的問(wèn)題就是幻讀問(wèn)題,因此這個(gè)算法只在 RR事務(wù)隔離級(jí)別中會(huì)使用
疑問(wèn)? 不是MVCC可以在無(wú)鎖的情況下解決幻讀的問(wèn)題嗎,為什么還要上next-key lock這么重的算法呢?這里就要引出兩個(gè)概念了,一致性非鎖定讀(快照讀) 和一致性鎖定讀(當(dāng)前讀) 的概念了
一致性非鎖定讀 : 我們平時(shí)使用的select * from table 這種查詢語(yǔ)句,都是快照讀,在innodb RC和RR級(jí)別下都是通過(guò)MVCC機(jī)制來(lái)實(shí)現(xiàn)的,過(guò)程中是不加鎖的,讀取的數(shù)據(jù)未必是當(dāng)前行中的真實(shí)的數(shù)據(jù)。
一致性鎖定讀 : select * from table for update 或者select * from table in shared mode 在這種情況下RC基本是會(huì)對(duì)對(duì)應(yīng)的行加鎖,RR級(jí)別下就會(huì)使用next-key算法加鎖。
六、redo日志
redo日志是物理日志,記錄的頁(yè)的物理修改日志
七、undo日志
undo日志是邏輯日志,記錄的是操作的sql邏輯,通常我們?cè)谛薷臄?shù)據(jù)的時(shí)候,先對(duì)行加鎖,然后將該版本的數(shù)據(jù)拷貝到undo日志中,然后修改當(dāng)前行的操作事務(wù)id,修改該行事務(wù),然后把回滾指針指向und日志。
七、MVCC
多版本控制(MVCC)在許多關(guān)系型數(shù)據(jù)庫(kù)中都有實(shí)現(xiàn),innodb中主要是依賴undo日志來(lái)實(shí)現(xiàn),其中涉及到的一個(gè)比較重要的概念就是read veiw
- low_limit_id :最大活躍事務(wù)id
- up_limit_id : 最小活躍事務(wù)id
- trx_ids : 活躍事務(wù)集合
- 如果當(dāng)前trx_id > low_limit_id,那數(shù)據(jù)一定是不可見(jiàn)的,因?yàn)閿?shù)據(jù)是在當(dāng)前事務(wù)開(kāi)啟后才修改的
- 如果當(dāng)前trx_id < up_limit_id,那么數(shù)據(jù)一定是可見(jiàn)的,因?yàn)槭聞?wù)在當(dāng)前事務(wù)開(kāi)啟前就已經(jīng)提交了
- 如果trx_id 在這之間,那么如果trx_id在trx_ids中,說(shuō)明事務(wù)還沒(méi)有提交,那么數(shù)據(jù)就不可見(jiàn), 否則事務(wù)就是可見(jiàn)的。
無(wú)論是在什么事務(wù)隔離級(jí)別下,基于read view的快照讀機(jī)制都相同的,只是創(chuàng)建read view的機(jī)制不太一樣。
在RR基本下,read view在事務(wù)開(kāi)啟的時(shí)候就創(chuàng)建完成了,二在RC級(jí)別下,每次查詢都會(huì)重新創(chuàng)建read view。
如果一個(gè)當(dāng)前事務(wù)為事務(wù)A, 另外一個(gè)事務(wù)是事務(wù)B, 如果事務(wù)A開(kāi)啟的時(shí)候,事務(wù)B已經(jīng)提交了,那么無(wú)論在RR級(jí)別或是RC級(jí)別下,B提交的數(shù)據(jù)對(duì)于事務(wù)A都是可見(jiàn)的; 如果B事務(wù)在A事務(wù)開(kāi)啟之前就已經(jīng)開(kāi)啟了,但是A啟動(dòng)的時(shí)候B事務(wù)還沒(méi)有提交,那么先讓無(wú)論RR級(jí)別還是RC級(jí)別,數(shù)據(jù)在快照讀模式下也都是不可見(jiàn)的;如果B事務(wù)在A開(kāi)啟之前就開(kāi)啟,但是在A事務(wù)提交前B事務(wù)就提交了,此時(shí)對(duì)于RR級(jí)別而言,B的trx_id在trx_ids之中(trx_ids是在開(kāi)啟事務(wù)的時(shí)候就已經(jīng)初始化了),那么RR級(jí)別下數(shù)據(jù)是可見(jiàn)的,但對(duì)于RC而言,重新生成的read view了,顯然數(shù)據(jù)就是可見(jiàn)的。
通過(guò)上述的分析,通過(guò)mvcc可以在RR級(jí)別下快照讀是完全解決了重復(fù)讀和幻讀的問(wèn)題,RC級(jí)別還是會(huì)有不可重復(fù)讀和幻讀的問(wèn)題,但是需要注意的是,MVCC只工作在快照讀(一致性非鎖定讀)條件下,對(duì)于當(dāng)前讀的問(wèn)題是無(wú)法走到MVCC的,所以一定要注意,MVCC只解決了快照讀的幻讀和不可重復(fù)讀問(wèn)題。
這里需要補(bǔ)充一個(gè)case來(lái)理解一下快照讀與當(dāng)前讀的巨大區(qū)別
CREATE TABLE `user_info` ( `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(10) NOT NULL DEFAULT '', `age` int(10) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) 事務(wù)隔離級(jí)別為RR
初始化數(shù)據(jù)
insert into user_info ('name', 'age') values ('jack', 1);
T1時(shí)刻A開(kāi)啟事務(wù),然后啟用快照讀
select * from user_info where id = 1;
查詢到的結(jié)果是
+----+------+-----+
| id | name | age |
+----+------+-----+
| 1 | tom | 0 |
+----+------+-----+
T2時(shí)刻我們開(kāi)啟事務(wù)B, 并且執(zhí)行
update user_info set age =1 where id = 1;
此時(shí)事務(wù)A中執(zhí)行當(dāng)前讀
select * from user_info where id = 1 for update;
事務(wù)A將會(huì)被阻塞 此時(shí)提交事務(wù)B,事務(wù)A中顯示的查詢結(jié)果為
+----+------+-----+
| id | name | age |
+----+------+-----+
| 1 | tom | 1 |
+----+------+-----+
然后我們?cè)俅螆?zhí)行一次快照讀
select * from user_info where id = 1;
獲得的結(jié)果為
+----+------+-----+
| id | name | age |
+----+------+-----+
| 1 | tom | 0 |
+----+------+-----+
通過(guò)上述的例子,可以看到,快照讀和當(dāng)前讀有著非常大的區(qū)別,在同一個(gè)事務(wù)當(dāng)中,快照讀和當(dāng)前讀返回的結(jié)果有可能是不一樣的。
我們看到,mvcc保證了快照讀每次讀取的數(shù)據(jù)是一致,next-key算法保證了當(dāng)前讀是一致。
到此這篇關(guān)于Mysql中的Innodb事務(wù)和鎖詳解的文章就介紹到這了,更多相關(guān)Innodb事務(wù)和鎖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL日志專項(xiàng)之redo log和undo log介紹
MySQL日志記錄了MySQL數(shù)據(jù)庫(kù)日常操作和錯(cuò)誤信息,MySQL有不同類型的日志文件(各自存儲(chǔ)了不同類型的日志),從日志當(dāng)中可以查詢到MySQL數(shù)據(jù)庫(kù)的運(yùn)行情況、用戶操作、錯(cuò)誤信息等2022-08-08Windows Server 2003 下配置 MySQL 集群(Cluster)教程
這篇文章主要介紹了Windows Server 2003 下配置 MySQL 集群(Cluster)教程,本文先是講解了原理知識(shí),然后給出詳細(xì)配置步驟和操作方法,需要的朋友可以參考下2015-06-06mysql ONLY_FULL_GROUP_BY設(shè)置sql_mode無(wú)效排查問(wèn)題(windows)
這篇文章主要介紹了mysql ONLY_FULL_GROUP_BY設(shè)置sql_mode無(wú)效排查問(wèn)題(windows),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-09-09在Mysql上創(chuàng)建數(shù)據(jù)表實(shí)例代碼
這篇文章主要介紹了如何在Mysql上創(chuàng)建數(shù)據(jù)表,需要的朋友可以參考下2014-03-03MySQL存儲(chǔ)過(guò)程和函數(shù)的操作(十二)
這篇文章主要為大家詳細(xì)介紹了MySQL存儲(chǔ)過(guò)程和函數(shù)的操作第十二篇,感興趣的小伙伴們可以參考一下2016-08-08MySQL中創(chuàng)建時(shí)間和更新時(shí)間的自動(dòng)更新的實(shí)現(xiàn)示例
本文主要介紹了MySQL中創(chuàng)建時(shí)間和更新時(shí)間的自動(dòng)更新的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-07-07徹底搞懂MySQL存儲(chǔ)過(guò)程和函數(shù)
我們大家都知道MySQL 存儲(chǔ)過(guò)程是從 MySQL 5.0 開(kāi)始逐漸增加新的功能,下面這篇文章主要給大家介紹了關(guān)于MySQL存儲(chǔ)過(guò)程和函數(shù)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04mysql數(shù)據(jù)庫(kù)索引損壞及修復(fù)經(jīng)驗(yàn)分享
這篇文章主要介紹了mysql數(shù)據(jù)庫(kù)索引損壞及修復(fù)經(jīng)驗(yàn)分享,需要的朋友可以參考下2015-06-06