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

MySQL InnoDB重复键场景下锁机制及异常行为相关问题咨询

MySQL 5.7 唯一键冲突锁机制问题解析

背景来源:mysql-refman-5.7

测试表结构与复现流程

表结构定义:

mysql> show create table t1 \G
*************************** 1. row ***************************
       Table: t1
Create Table: CREATE TABLE `t1` (
  `i` int(11) NOT NULL,
  PRIMARY KEY (`i`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)

初始表数据:

mysql> select * from t1;
Empty set (0.00 sec)

会话操作序列:

-- session1: 操作1
start transaction;
insert into t1 values(1);
-- session2: 操作2
insert into t1 values(1);
-- session3: 操作3
start transaction;
insert into t1 values(1);
-- session1: 操作4
rollback;

官方参考解释

  • 操作1执行后,session1获取主键值为1的行的排他锁(Exclusive Lock)
  • 操作2、3执行时会触发重复键检查逻辑,同时会申请对应行的共享锁(Shared Lock)
  • 操作4执行后,session1释放该行排他锁,session2、3获取到共享锁

问题解答

Q1:若操作4不执行,操作2、3执行后两个会话是否会一直等待该行的排他锁直至超时?为何此时没有出现“重复键错误”提示?

会等待直至超时,不会永久阻塞。
未抛出重复键错误的核心原因是:唯一键冲突校验逻辑需要先拿到待插入行的锁,才能读取到行的最新提交状态,完成冲突校验。session1持有行排他锁未释放时,session2、3的请求会先进入锁等待队列,还没到执行唯一键冲突校验的步骤,因此不会触发重复键报错。等待超过innodb_lock_wait_timeout参数配置的阈值后,会抛出锁超时错误,而非重复键错误。

Q2:触发重复键错误时,为何session2和session3会申请对应行的共享锁?两个会话不应该因异常直接结束执行吗?

InnoDB设计该逻辑是为了确认唯一键冲突的最终状态:待插入位置的已存在记录,可能是其他未提交事务写入的,若持有排他锁的事务后续回滚,当前插入操作实际可以执行成功。因此会话不会直接抛出异常结束,而是先申请共享锁,待拿到锁后读取行的最终提交状态,再判定是否真的存在冲突。如果拿到锁后发现原持有排他锁的事务已经回滚,行记录不存在,就可以继续完成插入;如果确认行已提交存在,才会抛出重复键错误。

Q3:重复键错误是否会作为错误消息主动抛出提示?

会主动抛出。只要锁等待完成后,最终确认存在已提交的同唯一键记录,就会返回1062 Duplicate entry 'xxx' for key 'xxx'的错误提示。只有锁等待未结束、或者锁超时的场景下,才不会抛出重复键错误。

Q4:为何重复键错误不会终止当前会话?

重复键错误属于单SQL语句级别的运行时错误,不属于会话级别的致命错误。MySQL的错误处理机制默认只会终止当前执行失败的单条SQL,不会中断整个会话连接,也不会自动回滚当前事务,用户可以自行选择回滚事务、调整SQL重新执行,或者提交事务中其他执行成功的操作。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 11:54:01