一. 事務隔離級別
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...