无锁场景下并发执行含唯一约束的saveAll操作是否会导致双方均失败?
会不会两个并发
saveAll请求都因唯一约束冲突失败? 答案是完全有可能,而且这种场景在高并发下并不少见,我来给你拆解一下背后的逻辑:
- 首先,你没加任何锁,意味着两个请求是完全并行执行的。数据库默认的事务隔离级别(比如READ COMMITTED)下,每个事务只能看到其他事务已经提交的数据。所以当两个请求同时执行
saveAll时,它们都看不到对方正在插入的未提交记录。 - 假设你们要保存的是同一组带唯一约束的记录,两个请求都会先完成自己的前置检查(如果有的话),然后同时向数据库发起插入操作。
- 数据库在处理这两个插入请求时,会分别校验唯一约束。由于两个请求的插入内容完全一致,两个请求都会在执行插入的瞬间触发“唯一键冲突”的错误——因为彼此都没提交,数据库无法提前感知重复,直到双方都试图写入时才会触发约束校验失败,最终导致两个
saveAll操作都失败(批量插入中只要有一条违反约束,通常整个批次都会回滚)。
举个具体例子:
你的表有唯一约束user_email,两个并发请求都要保存[{"id":1, "email":"test@example.com"}]。请求A和B同时启动,都查询数据库发现没有这个邮箱的记录,然后同时执行插入。这时候数据库会对两个插入请求分别做约束校验,结果两个都触发冲突错误,最终两个saveAll都执行失败。
如果要避免这种情况,你可以考虑这些方案:
- 在应用层加分布式锁,确保同一组记录的
saveAll操作同一时间只有一个请求在执行; - 调整数据插入逻辑,使用数据库的原子操作语句,比如
INSERT ... ON DUPLICATE KEY UPDATE(如果你的ORM支持的话),这样即使有冲突也不会失败,而是更新现有记录; - 做幂等处理,让重复的请求在触发约束时直接返回“成功”(前提是业务上允许这种情况)。
内容的提问来源于stack exchange,提问作者user1354825
相关产品推荐
相关产品推荐

