下面的讨论基于此表

CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `c` int(11) DEFAULT NULL,
  `d` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `c` (`c`)
) ENGINE=InnoDB;
insert into t values(0,0,0),(5,5,5),(10,10,10),(15,15,15),(20,20,20),(25,25,25);
  • show engine innodb status 命令输出的信息中,LATESTADETECTED DEADLOCK 记录了最后一次死锁信息

    • image.png
    • 由于锁是一个个加的,要避免死锁,对同一组资源,要按照尽量相同的顺序访问;
    • 在发生死锁的时刻,for update 这条语句占有的资源更多,回滚成本更大,所以 InnoDB 选择了回滚成本更小的 lock in share mode 语句,来回滚。
  • 所谓“间隙”,其实根本就是由“这个间隙右边的那个记录”定义的。

思考题

  • 空表的间隙的定义
    • 一个空表只有一个间隙
    • 比如执行:begin; select * from t where id>1 for update;
    • 加锁范围:next_key lock (-∞, supremum]

评论区

  • 删除数据,导致锁扩大的描述:“因此,我们就知道了,由于 delete 操作把 id=10 这一行删掉了,原来的两个间隙 (5,10)、(10,15)变成了一个 (5,15)。”我觉得这个提到的(5, 10) 和 (10, 15)两个间隙会让人有点误解,实际上在删除之前间隙锁只有一个(10, 15),删除了数据之后,导致间隙锁左侧扩张成了5,间隙锁成为了(5, 15)。