tips:

  • 以下测试如无特殊说明,隔离级别均为 MySQL 默认的 REPEATABLE READ 级;

  • 测试使用的 MySQL 版本为 8.0.43;

docker exec -it mysql /bin/bash
mysql -h127.0.0.1 -P3306 -uroot -p123456

一、分析前的一些准备工作

如何查看一个连接持有哪些锁

你可以使用下面的 SQL 语句来查询指定的连接持有哪些锁

-- 获取当前连接的 connection id
SELECT CONNECTION_ID() INTO @connection_id;

-- 根据 connection id 查询指定连接持有的锁
SELECT t2.*
FROM information_schema.innodb_trx t1
JOIN performance_schema.data_locks t2 ON t1.trx_id = t2.ENGINE_TRANSACTION_ID
WHERE t1.trx_mysql_thread_id =  @connection_id
;

在分析死锁 Case 时候,你可能会需要关闭死锁检测、延长锁超时时限来观察锁的情况:

SET GLOBAL innodb_deadlock_detect = OFF;
SET GLOBAL innodb_lock_wait_timeout = 9999999999;

-- 实验完成后记得改回去
SET GLOBAL innodb_deadlock_detect = ON;
SET GLOBAL innodb_lock_wait_timeout = 50;

测试数据表、模拟数据

如无特殊说明,这篇文章中的所有 Test Case 都基于下面这个表 t,每次测试完成后都需要重新执行一次下面的 SQL 以重置实验环境。

建表和初始化语句如下:

DROP TABLE IF EXISTS t;
CREATE TABLE t(
    id int(11) NOT NULL,
    a  int(11) DEFAULT NULL,
    c  int(11) DEFAULT NULL,
    d  int(11) DEFAULT NULL,
    
    PRIMARY KEY (id),
    unique index a(a),
    index c (c)
) ENGINE = InnoDB;

insert into t
values (0, 0, 0, 0)
     , (5, 5, 5, 5)
     , (10, 10, 10, 10)
     , (15, 15, 15, 15)
     , (20, 20, 20, 20)
     , (25, 25, 25, 25);
  • a 字段:唯一索引

  • c 字段:普通索引