ServiceStack OrmLite Save/SaveAsync操作触发主键Duplicate entry报错问题
报错原因
OrmLite默认Save/SaveAll的实现逻辑是先按主键查询记录是否存在,不存在则插入,存在则更新,整个流程无原子性保障。你遇到的主键重复报错是典型的竞态条件触发:两个同主键的写入请求同时查询主键存在性,都判定为不存在,先后执行插入操作,先执行的请求写入成功,后执行的请求触发主键冲突。
报错信息中主键值截断是MySQL错误提示的默认机制,仅为展示友好做的截断,和实际传入的主键值无关,无需额外排查。
解决方案
推荐方案:使用MySQL原生原子Upsert接口
OrmLite已针对MySQL场景原生提供基于INSERT ON DUPLICATE KEY UPDATE的原子Upsert实现,完全规避竞态问题,性能也优于默认查改分离逻辑,直接调用对应API即可:
- 单条记录Upsert:
db.InsertOnDuplicateKeyUpdate(待写入POCO实例); - 批量记录Upsert:
db.InsertAllOnDuplicateKeyUpdate(待写入POCO集合);
你使用的ServiceStack 5.13.1版本已支持上述API,无需升级版本。
兼容Save方法的临时方案
如果业务逻辑必须使用Save方法,可通过两种方式规避并发问题:
- 为同主键的Save操作加分布式锁,同一时间仅允许一个相同主键的Save请求执行
- 将Save逻辑包裹在显式事务中,查询主键存在性时使用
SELECT ... FOR UPDATE加行级锁,避免并发查询拿到相同判定结果
内容的提问来源于stack exchange,提问作者Ted
相关产品推荐
相关产品推荐

