注册接口并发提交同一手机号,两个请求都没立刻返回,一个 8 秒后成功,另一个报 1062 Duplicate entry,中间那 8 秒接口线程一直挂着。第一次遇到会往复杂处想,其实漏掉的多是个小前提。

SHOW INDEX FROM users WHERE Key_name = 'uk_phone';
SELECT * FROM performance_schema.data_locks
WHERE OBJECT_NAME = 'users' AND LOCK_TYPE = 'RECORD';

插入唯一键前要先做冲突检测,检测过程会给对应索引记录加锁。前一个事务没提交,后一个只能等它结束才知道要不要报 1062。等的是锁,不是唯一约束本身。这一点先确认清楚,后面就不用反复试。

「唯一键冲突锁等待」相关的验证我通常做两遍,改完一次、隔天再看一次,确认不是临时生效。把这次用到的命令存进笔记,比记住结论有用,换个环境还能照着走。

具体做法是,确认唯一索引存在且插入值确实会命中同一条记录;把注册流程改成先查后插 再加唯一索引兜底;捕获 1062 直接返回已注册 不要让请求挂在锁上;压测同一手机号并发 看等待时间是否收敛。

改完照着核一遍,并发注册同一手机号时只有一个请求写库 其余立刻返回已注册 接口耗时不再出现 8 秒的尖刺。

作者 9823189