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

PostgreSQL MERGE语句的WHEN NOT MATCHED子句是否线程安全?

PostgreSQL 15 MERGE语句在无唯一约束下的并发竞态问题分析

核心结论

在未给(book_id, user_id)创建唯一约束的前提下,你的MERGE语句无法阻止并发事务插入相同条件的行,WHEN NOT MATCHED子句存在竞态条件。

原因分析

MERGE的执行流程分为两步:

  1. 基于ON子句的条件(bb.book_id = source.book_id AND bb.user_id = source.user_id)扫描现有数据,判断是否存在匹配行;
  2. 根据匹配结果执行INSERT或UPDATE操作。

在没有唯一约束的场景下:

  • 当两个并发事务同时执行这条MERGE时,它们都会在扫描阶段发现表中没有对应(book_id, user_id)的行;
  • 随后两个事务都会进入WHEN NOT MATCHED分支执行插入操作,最终导致表中出现两条book_id和user_id完全相同的重复记录。

PostgreSQL不会在无唯一约束的情况下,自动对ON子句涉及的条件范围加排他锁来阻止并发插入,因此无法避免这种竞态。

解决方案

要彻底解决这个问题,必须为borrowed_books表添加(book_id, user_id)的唯一约束:

ALTER TABLE borrowed_books ADD CONSTRAINT unique_book_user UNIQUE (book_id, user_id);

添加约束后:

  • 当并发事务执行MERGE时,其中一个事务会成功插入数据;
  • 另一个事务会触发唯一约束冲突错误,此时可以通过捕获错误并重试的逻辑来保证最终数据的唯一性。

补充说明

MERGE语句仅会对扫描到的匹配行加锁,如果没有匹配行则不会持有任何锁,因此无法阻止其他事务插入相同条件的新行。唯一约束是PostgreSQL中保证并发场景下数据唯一性的可靠机制,底层会通过锁和约束检查来避免重复插入。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 19:52:40