You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL 8.0.26 RR隔离级别下主键supremum伪记录锁疑问

唯一键冲突后主键supremum伪记录锁的成因分析

环境与前提

  • MySQL版本:8.0.26
  • 事务隔离级别:REPEATABLE-READ(可重复读)

表结构

create table test
(
    id          int auto_increment primary key,
    a           varchar(256) null,
    b           int null,
    c           int null,
    create_time timestamp default CURRENT_TIMESTAMP null,
    constraint uni_key unique (a, b, c)
);

初始化数据

insert into test(a,b,c) values ('a',1,1);

会话操作流程

SessionASessionB
begin;begin;
insert into test(a,b,c) values ('a',1,1);
ERROR 1062 (23000): Duplicate entryinsert into test(a,b,c) values ('b',2,3);
(blocked)

Session B会被阻塞直到Session A提交。

锁信息查询结果

执行查询语句:

SELECT ENGINE_LOCK_ID as Lock_Id,
       ENGINE_TRANSACTION_ID as Trx_id, 
       OBJECT_NAME as `Table`,
       INDEX_NAME as `Index`, 
       LOCK_DATA as Data, 
       LOCK_MODE as Mode,
       LOCK_STATUS as Status,
       LOCK_TYPE as Type         
FROM performance_schema.data_locks;

返回结果:

+-----------------------------------------+--------+-------+---------+------------------------+------+---------+--------+
| Lock_Id                                 | Trx_id | Table | Index   | Data                   | Mode | Status  | Type   |
+-----------------------------------------+--------+-------+---------+------------------------+------+---------+--------+
| 140135522398208:1088:140135454819312    |  15656 | test  | NULL    | NULL                   | IX   | GRANTED | TABLE  |
| 140135522398208:23:5:27:140135454816400 |  15656 | test  | uni_key | 'a', 1, 1, 64          | S    | GRANTED | RECORD |
| 140135522398208:23:4:1:140135454817088  |  15656 | test  | PRIMARY | supremum pseudo-record | X    | GRANTED | RECORD |
+-----------------------------------------+--------+-------+---------+------------------------+------+---------+--------+
3 rows in set (0.01 sec)

问题解答

1. 唯一键冲突后主键supremum伪记录锁的成因

当SessionA执行插入触发唯一键冲突时,InnoDB的处理逻辑如下:

  • 首先在冲突的唯一键uni_key上加S锁,防止其他事务修改这条冲突记录,避免数据不一致或幻读;
  • 其次,InnoDB内部会先尝试为新插入行分配自增主键(即使插入最终失败)。由于自增主键必然大于现有所有主键值,会定位到主键索引的supremum伪记录(InnoDB为索引末尾虚拟的边界记录),并给这个伪记录加X锁。目的是阻塞其他事务插入新的自增主键行,保证可重复读隔离级别下的事务一致性视图,避免其他事务的插入操作破坏当前事务的冲突状态判断。

2. 无冲突时SessionB可执行的原因

当SessionA插入无唯一键冲突时:

  • 成功分配自增主键并将数据插入主键索引和唯一键索引;
  • 事务未提交时仅持有自身插入记录的锁,SessionB插入的记录在主键和唯一键上的位置与SessionA的记录无重叠,无需获取被持有的锁,因此可以正常执行。

3. 唯一键错误的处理逻辑

InnoDB检测到唯一键冲突时:

  1. 先完成冲突检测,确认唯一键已存在;
  2. 不会立即释放已持有的锁(包括唯一键的S锁和主键的supremum X锁),因为当前事务仍处于未提交/未回滚状态;
  3. 抛出1062错误,但事务不会自动回滚(默认参数下),直到SessionA主动提交或回滚,锁才会释放,SessionB才能继续执行。

这种锁的持有逻辑是为了保证事务的原子性和隔离性,避免事务未结束前其他事务修改相关数据导致冲突状态被破坏。


内容的提问来源于stack exchange,提问作者supergaga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 15:05:04