如何实现带锁的记录更新(不存在则插入)并判断锁状态?
问题分析与实现方案
你遇到的核心问题是对MySQL LOCK TABLE的返回逻辑理解有误——这个语句不会返回布尔值表示锁是否获取成功:它执行成功就返回正常状态,只有当无法获取锁(比如超时、权限不足)时才会抛出错误,这就是并发场景下你看到它始终返回"成功"的原因。
符合你需求的正确执行流程
按照你指定的"先更新,无影响则锁表插入"逻辑,正确的实现步骤如下:
- 执行更新语句并获取影响行数
UPDATE x SET y=1 WHERE id=5; - 根据影响行数分支处理:
- 若影响行数>0:流程结束
- 若影响行数=0:执行锁表插入逻辑:
-- 对表x加写锁,确保当前会话独占写入权限 LOCK TABLE x WRITE; -- 锁表后必须再次检查记录是否存在(并发场景下的关键校验) SELECT COUNT(*) FROM x WHERE id=5; -- 确认记录仍不存在时执行插入 IF COUNT(*) = 0 THEN INSERT INTO x(id, y) VALUES(5, 1); END IF; -- 释放表锁 UNLOCK TABLES;
必须注意的细节
- 锁表后的二次检查不可省略:在你执行完
UPDATE到获取锁的这段窗口,可能有其他会话已经插入了目标记录,直接插入会触发主键/唯一键冲突,所以必须在锁表后再次校验。 - 关于
LOCK TABLE的行为:MySQL的表锁默认是阻塞式的(除非设置LOCK TABLES ... NOWAIT),如果表已被其他会话锁定,当前会话会进入等待,直到获取锁或超时抛出错误,不会返回"false"。
内容的提问来源于stack exchange,提问作者John Smith
相关产品推荐
相关产品推荐

