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

无法复现‘CREATE IF NOT EXISTS’SQL的主键冲突错误求助

点赞操作主键冲突问题分析

问题背景

我用以下SQL语句实现用户点赞的“存在则不插入”逻辑,持久化到Azure SQL数据库:

if not exists(
    select 1 from likes 
    where UserId = @UserId and EntityId = @EntityId and EntityType = @EntityType)

insert into likes (UserId, EntityType, EntityId) 
values (@UserId, @EntityType, @EntityId)

Likes表无Id列,主键为(UserId, EntityType, EntityId)。直接查询和API测试都正常,点赞已存在时数据库无变化,但近期出现主键冲突错误:

Violation of PRIMARY KEY constraint 'PK_Likes'. Cannot insert duplicate key in object 'dbo.Likes'. The duplicate key value is (19, 1, 113). The statement has been terminated.

无法复现该错误,请求分析原因。

可能的原因

  • 并发写入竞争:这是最核心的原因。当多个相同的点赞请求同时抵达数据库时,两个请求会先后执行IF NOT EXISTS查询——此时都查不到对应记录,接着同时执行INSERT操作,就触发了主键冲突。因为IF NOT EXISTS和INSERT是两个独立操作,中间存在时间窗口,并发场景下会绕过检查逻辑。
  • 事务隔离级别导致的不可重复读:默认的READ COMMITTED隔离级别下,一个事务执行INSERT后还未提交,另一个事务的IF NOT EXISTS查询看不到这条未提交的记录,就会重复插入。
  • Azure SQL的瞬时同步延迟:极端情况下,Azure SQL的节点间同步、日志写入存在短暂延迟,可能导致刚插入的记录无法被紧接着的IF NOT EXISTS查询读取到,进而触发重复插入。
  • 客户端重复请求:前端按钮防抖失效、网络重试机制触发,导致同一用户的点赞请求被多次发送,且这些请求刚好落在数据库的检查时间窗口内。

解决方案建议

  • 改用原子性的MERGE语句:把IF NOT EXISTS和INSERT合并成一个原子操作,彻底避免并发竞争:
MERGE INTO likes AS target
USING (SELECT @UserId AS UserId, @EntityType AS EntityType, @EntityId AS EntityId) AS source
ON (target.UserId = source.UserId AND target.EntityType = source.EntityType AND target.EntityId = source.EntityId)
WHEN NOT MATCHED THEN
    INSERT (UserId, EntityType, EntityId)
    VALUES (source.UserId, source.EntityType, source.EntityId);
  • 前端添加防抖处理:给点赞按钮加防抖,比如1秒内只允许触发一次请求,避免用户快速点击导致重复提交。
  • API层捕获异常:在代码里捕获主键冲突的异常,返回“您已点赞过”的提示即可,不影响正常业务流程。
  • 调整事务隔离级别(谨慎使用):可以尝试将事务隔离级别设为REPEATABLE READ,但这会增加锁竞争,可能影响数据库性能,需要根据实际业务场景权衡。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 01:22:40