Innodb事務和鎖總結

2021-10-23 06:37:34 字數 4488 閱讀 4490

一. 事務隔離級別

read uncommited:讀未提交,事務之間可以看到彼此之間正在修改的內容,會出現所謂的髒讀現象

read commited: 讀已提交,只能讀取已經提交的事務修改的資料,不會出現髒讀的現象,但會出現不可重複讀和幻讀的情況

repeatable read: 可重複度,在innodb中解決了不可重複讀和幻讀的問題

serialized: 序列化, 這個使用的比較少,隔離性最強,效能也最差

二. 鎖型別

s lock: 共享鎖 : s鎖與s鎖相互相容,與x鎖不相容

x lock:排他鎖 :與其他所有鎖型別不相容,

簡單的可以理解為讀寫鎖即可

意向鎖 (is, ix) :主要是用來表達加鎖的一種層次概念,比如希望在行級別加x鎖,那麼就需要在表級和頁級別加上ix鎖,意向鎖整體上相容性會比較好,如果當前表中已經有了多個行級鎖,如果希望嘗試加表鎖,如果沒有意向鎖的話,那麼就需要取檢測當前行鎖的加鎖情況,但是有了意向鎖,就可以快速判斷當前嘗試加表鎖可能是需要等待的。

監控方法

show engine innodb status命令檢視innodb引擎資訊,其中包含當前執行事務的狀態和鎖的狀態

通過information_schema提供的表來排查可能存在的問題

a. information_schema.innodb_trx

b. information_schema.innodb_locks

c. innodb_lock_waits

三.鎖釋放的時機

lock通常在事務commit或是rollback之後才會釋放

四. 一致性非鎖定讀

這是非常常見的問題,事務中會有大量的select操作,select操作通常情況下是不會對資料做加鎖操作的, 這樣保證了資料的併發效能,在不同的事務隔離級別下,非一致性鎖定讀的行為是不太一樣的

read commited : 讀取undo_log中該行最新的一條快照資料

read repetable : 讀取undo_log中,最近的早於當前事務開啟時間的快照資料

五. 加鎖演算法

上文描述了鎖的型別,即排它鎖,共享鎖,意向鎖之類,這裡所說的是加鎖的演算法,即為innodb使用了什麼樣的加鎖策略來處理實際場景中的併發問題。

3. record lock : 行鎖,對單個行記錄進行加鎖,行是innodb的最小資料管理單位,innodb中有專門的資料結構來儲存和管理行記錄,我們所有的查詢的資料最終都會落到儲存引擎的行上,具體行,頁,表的概念可以參考《innodb儲存引擎》一書

2.gap lock : 間隙鎖,即對間隙加鎖,間隙其實就這裡只是針對間隙,不包括行(todo ,間隙的概念需要搞一下)

4. next-key lock : 對行和間隙和行都進行加鎖

netx-key lock演算法主要解決的問題就是幻讀問題,因此這個演算法只在 rr事務隔離級別中會使用

疑問? 不是mvcc可以在無鎖的情況下解決幻讀的問題嗎,為什麼還要上next-key lock這麼重的演算法呢?這裡就要引出兩個概念了,一致性非鎖定讀(快照讀) 和一致性鎖定讀(當前讀) 的概念了

一致性非鎖定讀 : 我們平時使用的select * from table 這種查詢語句,都是快照讀,在innodb rc和rr級別下都是通過mvcc機制來實現的,過程中是不加鎖的,讀取的資料未必是當前行中的真實的資料。

一致性鎖定讀 : select * from table for update 或者select * from table in shared mode 在這種情況下rc基本是會對對應的行加鎖,rr級別下就會使用next-key演算法加鎖。

六、redo日誌

redo日誌是物理日誌,記錄的頁的物理修改日誌

七、undo日誌

undo日誌是邏輯日誌,記錄的是操作的sql邏輯,通常我們在修改資料的時候,先對行加鎖,然後將該版本的資料拷貝到undo日誌中,然後修改當前行的操作事務id,修改該行事務,然後把回滾指標指向und日誌。

七、mvcc

多版本控制(mvcc)在許多關係型資料庫中都有實現,innodb中主要是依賴undo日誌來實現,其中涉及到的乙個比較重要的概念就是read veiw

low_limit_id :最大活躍事務id

up_limit_id : 最小活躍事務id

trx_ids : 活躍事務集合

如果當前trx_id > low_limit_id,那資料一定是不可見的,因為資料是在當前事務開啟後才修改的

如果當前trx_id < up_limit_id,那麼資料一定是可見的,因為事務在當前事務開啟前就已經提交了

如果trx_id 在這之間,那麼如果trx_id在trx_ids中,說明事務還沒有提交,那麼資料就不可見, 否則事務就是可見的。

無論是在什麼事務隔離級別下,基於read view的快照讀機制都相同的,只是建立read view的機制不太一樣。

在rr基本下,read view在事務開啟的時候就建立完成了,二在rc級別下,每次查詢都會重新建立read view。

如果乙個當前事務為事務a, 另外乙個事務是事務b, 如果事務a開啟的時候,事務b已經提交了,那麼無論在rr級別或是rc級別下,b提交的資料對於事務a都是可見的; 如果b事務在a事務開啟之前就已經開啟了,但是a啟動的時候b事務還沒有提交,那麼先讓無論rr級別還是rc級別,資料在快照讀模式下也都是不可見的;如果b事務在a開啟之前就開啟,但是在a事務提交前b事務就提交了,此時對於rr級別而言,b的trx_id在trx_ids之中(trx_ids是在開啟事務的時候就已經初始化了),那麼rr級別下資料是可見的,但對於rc而言,重新生成的read view了,顯然資料就是可見的。

通過上述的分析,通過mvcc可以在rr級別下快照讀是完全解決了重複讀和幻讀的問題,rc級別還是會有不可重複讀和幻讀的問題,但是需要注意的是,mvcc只工作在快照讀(一致性非鎖定讀)條件下,對於當前讀的問題是無法走到mvcc的,所以一定要注意,mvcc只解決了快照讀的幻讀和不可重複讀問題。

這裡需要補充乙個case來理解一下快照讀與當前讀的巨大區別

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`)

)事務隔離級別為rr

初始化資料

insert into user_info ('name', 'age') values ('jack', 1);
t1時刻a開啟事務,然後啟用快照讀

select * from user_info where id = 1;
查詢到的結果是

+----+------+-----+

| id | name | age |

+----+------+-----+

| 1 | tom | 0 |

+----+------+-----+

t2時刻我們開啟事務b, 並且執行

update user_info set age =1 where id = 1;
此時事務a中執行當前讀

select * from user_info where id = 1 for update;
事務a將會被阻塞

此時提交事務b,事務a中顯示的查詢結果為

+----+------+-----+

| id | name | age |

+----+------+-----+

| 1 | tom | 1 |

+----+------+-----+

然後我們再次執行一次快照讀

select * from user_info where id = 1;
獲得的結果為

+----+------+-----+

| id | name | age |

+----+------+-----+

| 1 | tom | 0 |

+----+------+-----+

通過上述的例子,可以看到,快照讀和當前讀有著非常大的區別,在同乙個事務當中,快照讀和當前讀返回的結果有可能是不一樣的。

我們看到,mvcc保證了快照讀每次讀取的資料是一致,next-key演算法保證了當前讀是一致。

Innodb 鎖實現事務隔離性

鎖mvcc隔離級別的實現 概述 用來維護事務的一致性和隔離性,在高併發場景下,如果加鎖過度,會極大的降低併發處理能力 分類 記錄鎖 鎖乙個索引記錄,表中沒有索引時,會自動為主鍵建立乙個聚簇索引 間隙鎖 鎖兩個索引記錄的間隙 或 第乙個索引記錄的前面 或 最後乙個索引記錄的後面的間隙 next key...

學習總結 INNODB 事務併發

innodb的讀資料總是一致的,如果在session 1讀的過程中,session 2對資料進行修改,不管session 2是否提交,在session 1的事務中都會讀到修改前的值。讀操作保持一致性並不受阻塞的原因是多版本機制。所謂多版本機制是指innodb會儲存被修改資料的舊版本,以支援併發和回滾...

mysql主流Innodb儲存引擎 事務鎖分析

repeatable read 可重讀 mysql中innodb預設的隔離級別。悲觀鎖 為了防止併發導致資料庫操作受其他執行緒運算元據庫影響,一般基於資料庫的悲觀鎖來加鎖操作。從sql語句來看,為了搶占獨佔鎖,兩種方式。1 更新語句加鎖 begin 開啟事務 insert into a.update...