總的來說,InnoDB 共有七種類型的鎖:
(1) 共享/排它鎖(Shared and Exclusive Locks)
(2) 意向鎖(Intention Locks)
(3) 記錄鎖(Record Locks)
(4) 間隙鎖(Gap Locks)
(5) 臨鍵鎖(Next-key Locks)
(6) 插入意向鎖(Insert Intention Locks)
(7) 自增鎖(Auto-inc Locks)
下面將結(jié)合案例,剖析 InnoDB 的自增鎖
案例
MySQL,InnoDB,默認的隔離級別(RR),假設有數(shù)據(jù)表:t(id AUTO_INCREMENT, name);
數(shù)據(jù)表中有數(shù)據(jù):
- shenjian
- zhangsan
- lisi
事務A先執(zhí)行,還未提交:
insert into t(name) values(xxx);
事務B后執(zhí)行:
insert into t(name) values(ooo);
問:事務B會不會被阻塞?
分析
InnoDB在RR隔離級別下,能解決幻讀問題,上面這個案例中:
(1) 事務A先執(zhí)行insert,會得到一條(4, xxx)的記錄,由于是自增列,故不用顯示指定id為4,InnoDB會自動增長,注意此時事務并未提交;
(2) 事務B后執(zhí)行insert,假設不會被阻塞,那會得到一條(5, ooo)的記錄;
此時,并未有什么不妥,但如果
(3) 事務A繼續(xù)insert:
insert into t(name) values(xxoo);
會得到一條(6, xxoo)的記錄。
(4) 事務A再select:
select * from t where id>3;
得到的結(jié)果是:
4, xxx
6, xxoo
那么,就不可能查詢到5的記錄,再RR的隔離級別下,不可能讀取到還未提交事務生成的數(shù)據(jù)。這對于事務A來說,就很奇怪了,對于AUTO_INCREMENT的列,連續(xù)插入了兩條記錄,一條是4,接下來一條變成了6。
自增鎖
自增鎖是一種特殊的表級別鎖(table-level lock),專門針對事務插入AUTO_INCREMENT類型的列。最簡單的情況,如果一個事務正在往表中插入記錄,所有其他事務的插入必須等待,以便第一個事務插入的行,是連續(xù)的主鍵值。
與此同時,InnoDB 提供了 innodb_autoinc_lock_mode 配置,可以調(diào)節(jié)與改變該鎖的模式與行為。
上面的案例,假設不是自增列,又會是什么樣的情形呢?
t(id unique PK, name);
數(shù)據(jù)表中有數(shù)據(jù):
10, shenjian
20, zhangsan
30, lisi
事務A先執(zhí)行,在10與20兩條記錄中插入了一行,還未提交:
insert into t values(11, xxx);
事務B后執(zhí)行,也在10與20兩條記錄中插入了一行:
insert into t values(12, ooo);