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