不使用索引
CREATE TABLE `test1` (
`id` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
BEGIN;
-- 手動開啓一個事務,並在id = 1這條數據上加上排它鎖
SELECT * from test1 WHERE id = 1 for UPDATE;
BEGIN;
-- 手動開啓另外一個事務,此時給id=2的這條數據進行加排它鎖,結果會如何?
SELECT * from test1 WHERE id = 2 for UPDATE
發現此時居然查詢id=2的數據事務被卡住了。這是爲什麼呢?當表沒有創建索引時或者查詢語句沒有命中索引時,鎖住的是整個表的數據,因爲沒有命中索引故其會去掃描全表數據。 當一張表沒有索引時,innoDB會創建一個隱藏主鍵索引,當通過隱藏的主鍵索引去檢索時,將該表中所有的隱藏索引檢索一遍 例子:如果手動開始事務,並在id=1的數據上手動加上排它鎖.如果此時再去查詢id=2的數據時,發現此語句卡住了。 故得出沒有建立索引的表,一旦鎖住數據及爲鎖住整張表。
主鍵索引
CREATE TABLE `test2` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
BEGIN;
-- 主鍵索引
SELECT * from test2 WHERE id = 1 FOR UPDATE;
BEGIN;
-- 手動開啓其他事務
SELECT * from test2 WHERE id = 5 for update;
此時說明,主鍵索引時只會鎖住匹配到的索引項,而不會影響其他事務操作其他索引
唯一索引
CREATE TABLE `test3` (
`id` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `unique_name` (`name`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
BEGIN;
-- 唯一索引
SELECT * from test3 where name = '李四' FOR update;
BEGIN;
-- 唯一索引
SELECT * from test3 where id= 5 FOR update;
注意:此時SELECT * from test3 where id= 5 FOR update爲什麼執行卡住了?唯一索引鎖定時,先通過唯一索引然後找到對應主鍵索引,也就是輔助索引--->主鍵索引的一個過程,所以查詢id = 5的數據時也被鎖住了。 通過上面幾個例子發現mysql innodb是通過鎖住索引來實現行鎖的
mysql innodb 爲什麼不會出現幻讀?
詳見下面InnoDB的行鎖,如下圖 臨界鎖的操作
臨界鎖(Next-key Lock)鎖定範圍加記錄
BEGIN;
-- 臨界鎖,鎖住對應的範圍,防止幻讀。
-- 按道理此時應該鎖住,6,7,8(已存在),9,10
SELECT * from test2 WHERE id > 5 and id <11 FOR UPDATE;
BEGIN;
-- 此時測試插入id=7 的值,按道理應該插入不進去,因爲鎖住的範圍是(5,8]和(8,12]
insert into test2 VALUES(7,'試試');
BEGIN;
SELECT * from test2 WHERE id = 12 FOR UPDATE;
剛纔不是id>5 and id <11的麼?此時爲什麼id =12也被鎖了呢?因爲此時鎖住的範圍是(5,8]和(8,12]
Gap Lock(間隙鎖)
BEGIN;
-- 間隙鎖,因爲id =7 這條數據不存在,故鎖退化成了間隙鎖,那麼此時id=7 落在了(5,8)這個區間
SELECT * from test2 where id = 7 for UPDATE;
BEGIN;
-- 因爲鎖退化成了間隙鎖,那麼此時id=7 落在了(5,8)這個區間,故id =6 也一起被鎖住了
INSERT into test2 VALUES(6,'卡卡');
Record Lock(記錄鎖)
注意: 測試在test2表中,也就是主鍵索引。
BEGIN;
-- 在事務1中在id =5 的主鍵項鎖定
SELECT * from test2 where id = 5 for update;
本文是摘抄的,原文路徑: https://my.oschina.net/u/3370769/blog/3000934
自己補充點東西把,自己不理解的地方也做下筆記。
間隙鎖(gap lock),鎖住的是一個區間範圍,比如鎖住區間(1,3),如果插入2的數據是插入不進去的,1和3是開區間,因此,1和3不受影響。
臨界鎖(next key lock),鎖住索引上的記錄+前面的間隙鎖,是一個左開右閉區間,比如(1,3]。一個next-key鎖=索引上的記錄鎖+鎖住前面間隙的gap lock。