一,案例說明spa
MySQL,InnoDB,默認的隔離級別(RR),假設有數據表:事務
t(id AUTO_INCREMENT, name);ci
數據表中有數據:it
1, shenjianio
2, zhangsaninnodb
3, lisitable
事務A先執行,還未提交:配置
insert into t(name) values(xxx);select
事務B後執行:im
insert into t(name) values(ooo);
問:事務B會不會被阻塞?
二,案例分析
InnoDB在RR隔離級別下,能解決幻讀問題,上面這個案例中:
(1)事務A先執行insert,會獲得一條(4, xxx)的記錄,因爲是自增列,故不用顯示指定id爲4,InnoDB會自動增加,注意此時事務並未提交;
(2)事務B後執行insert,假設不會被阻塞,那會獲得一條(5, ooo)的記錄;
此時,並未有什麼不妥,但若是,
(3)事務A繼續insert:
insert into t(name) values(xxoo);
會獲得一條(6, xxoo)的記錄。
(4)事務A再select:
select * from t where id>3;
獲得的結果是:
4, xxx
6, xxoo
畫外音:不可能查詢到5的記錄,再RR的隔離級別下,不可能讀取到還未提交事務生成的數據。
咦,這對於事務A來講,就很奇怪了,對於AUTO_INCREMENT的列,連續插入了兩條記錄,一條是4,接下來一條變成了6,就像莫名其妙的幻影。
三,自增鎖(Auto-inc Locks)
自增鎖是一種特殊的表級別鎖(table-level lock),專門針對事務插入AUTO_INCREMENT類型的列。最簡單的狀況,若是一個事務正在往表中插入記錄,全部其餘事務的插入必須等待,以便第一個事務插入的行,是連續的主鍵值。
畫外音:官網是這麼說的
An AUTO-INC lock is a special table-level lock taken by transactions inserting into tables with AUTO_INCREMENT columns. In the simplest case, if one transaction is inserting values into the table, any other transactions must wait to do their own inserts into that table, so that rows inserted by the first transaction receive consecutive primary key values.
與此同時,InnoDB提供了innodb_autoinc_lock_mode配置,能夠調節與改變該鎖的模式與行爲。
四,假如不是自增列
上面的案例,假設不是自增列,又會是什麼樣的情形呢?
t(id unique PK, name);
數據表中有數據:
10, shenjian
20, zhangsan
30, lisi
事務A先執行,在10與20兩條記錄中插入了一行,還未提交:
insert into t values(11, xxx);
事務B後執行,也在10與20兩條記錄中插入了一行:
insert into t values(12, ooo);
這裏,便再也不使用自增鎖,那:
(1)會使用什麼鎖?
(2)事務B會不會被阻塞呢?