使用INSERT INTO ... WHERE NOT EXISTS判断主键不存在再插入结果报错

cn_newer 2025-04-02 15:13:35

Linux环境:SUSE 15 sp3

在执行pgsql语句时候,先判断主键不存在再插入数据,结果报错。

基本的语句如下(省略了多余的内容):

INSERT INTO image ( image_uuid, image_series_uuid )

SELECT 'd9aaf41a-9c88-488b-b371-0c0bb1165a4f', '85c4a85a-10de-47d3-8af5-1c090e119a86' 

WHERE NOT EXISTS (

     SELECT 1 FROM image WHERE image_uuid = 'd9aaf41a-9c88-488b-b371-0c0bb1165a4f'

);

报错如下:

duplicate key value violates unique constraint "image_pkey"
--------
DETAIL:  Key (image_uuid)=(d9aaf41a-9c88-488b-b371-0c0bb1165a4f) already exists.
SCHEMA NAME:  public
TABLE NAME:  image
CONSTRAINT NAME:  image_pkey
_bt_check_unique, nbtinsert.c:656

这时候数据库可能处于checkpoint状态,执行有一个平时几十毫秒的事务花费4s多。

...全文
42 4 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
4 条回复
切换为时间正序
请发表友善的回复…
发表回复
trainee 04-03
  • 打赏
  • 举报
回复

你SELECT 未加锁,可能出现2个进程同时操作该语句,特别在并发量大的情况下
两个解决方法:
1、SELECT后面加排它锁 FOR UPDATE
2、INSERT 加语句 ON DUPLICATE KEY DO NOTING,主键存在时不插入

建议用第2种方法

cn_newer 04-07
  • 举报
回复
@trainee 你好,SELECT如何加锁呢?
trainee 04-08
  • 举报
回复 1
@cn_newer SELECT语句后面跟FOR UPDATE, 其实你已经有主键约束,多这个SELECT语句是画蛇添足,直接INSERT INTO不是更好,你上面报错是因为并发条件下两个一样的语句同时执行,一个已经成功,另一个因为主键约束肯定是不成功。忽略他不就行了吗?如果要不让它报错,就用INSERT INTO ... ON CONFLICT .. DO NOTHING
cn_newer 04-08
  • 举报
回复
@trainee 感谢

971

社区成员

发帖
与我相关
我的任务
社区描述
PostgreSQL相关内容讨论
sql数据库数据库架构 技术论坛(原bbs)
社区管理员
  • PostgreSQL社区
  • yang_z_1
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧