mysql 8.0.x
我们坚持混淆 SELECT ... LIMIT 1 FOR UPDATE SKIP LOCKED 的不同行为取决于主索引字段类型。
让我们考虑 2 个类似表的情况。
情况1:
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
案例2:
CREATE TABLE `test` (
`id` binary(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
它们仅在字段类型上有所不同 - INT 和 BINARY。
插入 6 个 id 为 1 到 6 的项目。
运行 2 个并发事务。
Transaction 1:
BEGIN;
SELECT id FROM test
LIMIT 1
FOR UPDATE skip locked;
SELECT SLEEP(10); #for test
COMMIT;
交易2:
BEGIN;
SELECT id
FROM test
WHERE id = 4
FOR UPDATE;
COMMIT;
如果 id 是一个 INT 字段,则 select ... for update from transaction 2 执行时无需等待第一个事务提交。
如果 id 是二进制文件 select ... for update from transaction 2 在第二个事务提交后执行
第二种情况的 SHOW ENGINE INNODB STATUS 输出的一部分:
---TRANSACTION 38229, ACTIVE 3 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 12, OS thread handle 6068, query id 1532 localhost 127.0.0.1 root Sending data
SELECT id
FROM test
where id = 4
FOR UPDATE
------- TRX HAS BEEN WAITING 3 SEC FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 19 page no 4 n bits 80 index PRIMARY of table `test`.`test` trx id 38229 lock_mode X waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 11; hex 3100000000000000000000; asc 1 ;;
1: len 6; hex 000000009530; asc 0;;
2: len 7; hex 80000000000000; asc ;;
------------------
---TRANSACTION 38228, ACTIVE 5 sec
2 lock struct(s), heap size 1136, 1 row lock(s)
MySQL thread id 8, OS thread handle 12052, query id 1530 localhost 127.0.0.1 root User sleep
SELECT SLEEP(10)
-----------------------------
这是一个很大的惊喜...
谁能解释为什么mysql(innodb)在这些情况下表现如此不同。