總的來說,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谢肾,默認(rèn)的隔離級別(RR)旗扑,假設(shè)有數(shù)據(jù)表:t(id AUTO_INCREMENT, name);
數(shù)據(jù)表中有數(shù)據(jù):
- shenjian
- zhangsan
- lisi
事務(wù)A先執(zhí)行捎谨,還未提交:
insert into t(name) values(xxx);
事務(wù)B后執(zhí)行:
insert into t(name) values(ooo);
問:事務(wù)B會不會被阻塞?
分析
InnoDB在RR隔離級別下禀酱,能解決幻讀問題炬守,上面這個案例中:
(1) 事務(wù)A先執(zhí)行insert,會得到一條(4, xxx)的記錄剂跟,由于是自增列劳较,故不用顯示指定id為4,InnoDB會自動增長浩聋,注意此時事務(wù)并未提交观蜗;
(2) 事務(wù)B后執(zhí)行insert,假設(shè)不會被阻塞衣洁,那會得到一條(5, ooo)的記錄墓捻;
此時,并未有什么不妥坊夫,但如果
(3) 事務(wù)A繼續(xù)insert:
insert into t(name) values(xxoo);
會得到一條(6, xxoo)的記錄砖第。
(4) 事務(wù)A再select:
select * from t where id>3;
得到的結(jié)果是:
4, xxx
6, xxoo
那么,就不可能查詢到5的記錄环凿,再RR的隔離級別下梧兼,不可能讀取到還未提交事務(wù)生成的數(shù)據(jù)。這對于事務(wù)A來說智听,就很奇怪了羽杰,對于AUTO_INCREMENT的列渡紫,連續(xù)插入了兩條記錄,一條是4考赛,接下來一條變成了6惕澎。
自增鎖
自增鎖是一種特殊的表級別鎖(table-level lock),專門針對事務(wù)插入AUTO_INCREMENT類型的列颜骤。最簡單的情況唧喉,如果一個事務(wù)正在往表中插入記錄,所有其他事務(wù)的插入必須等待忍抽,以便第一個事務(wù)插入的行八孝,是連續(xù)的主鍵值。
與此同時鸠项,InnoDB 提供了 innodb_autoinc_lock_mode 配置干跛,可以調(diào)節(jié)與改變該鎖的模式與行為。
上面的案例锈锤,假設(shè)不是自增列驯鳖,又會是什么樣的情形呢闲询?
t(id unique PK, name);
數(shù)據(jù)表中有數(shù)據(jù):
10, shenjian
20, zhangsan
30, lisi
事務(wù)A先執(zhí)行久免,在10與20兩條記錄中插入了一行,還未提交:
insert into t values(11, xxx);
事務(wù)B后執(zhí)行扭弧,也在10與20兩條記錄中插入了一行:
insert into t values(12, ooo);