MySQL Repeatable Read隔离级别下能否用Select For Update实现实体名唯一性?
问题解答
1. 能否使用SELECT FOR UPDATE解决该场景问题
可以,该方案完全适配你的需求:可在Repeatable Read隔离级别下正常运行,不会触发唯一约束冲突,也无需降级到Serializable隔离级别。
具体实现逻辑如下:
- 开启事务(保持默认的Repeatable Read隔离级别即可)
- 执行查询:
SELECT id FROM application_domains WHERE org_id = ? AND name = ? FOR UPDATE;注意必须同时传入org_id和待校验的name作为查询条件 - 若查询返回记录,说明该名称已被占用,直接终止事务并返回冲突提示
- 若查询无返回记录,执行对应的新增/更新操作,完成后提交事务
InnoDB在Repeatable Read级别下,针对不存在的记录执行SELECT FOR UPDATE会自动加间隙锁,阻塞其他事务插入相同org_id + name组合的记录,从根源上避免并发插入冲突,不会触发唯一约束异常。
2. 关于锁全表的假设确认
你的假设仅在查询条件未命中任何索引、触发全表扫描的场景下成立,当前场景只要正确写查询条件就不会出现锁全表的问题:
你提供的表结构中存在唯一联合索引UK_orgId_name (org_id, name),只要查询条件同时包含org_id和name两个字段,就会命中该唯一索引,InnoDB只会锁定该查询条件对应的行(记录存在时)或对应索引范围的间隙(记录不存在时),不会锁定整张表,也不会影响其他组织下的名称申领操作,并发性能可控。
如果你的查询条件仅包含name、未携带org_id,无法命中有效索引才会触发全表扫描,进而锁全表,只要规避这种写法即可。
内容的提问来源于stack exchange,提问作者Ihor M.
相关产品推荐
相关产品推荐

