【问题标题】:How to prevent duplicate insert with insert return in postgres?如何防止在postgres中插入返回重复插入?
【发布时间】:2019-02-07 08:47:11
【问题描述】:

我正在尝试为我的数据库创建一些规则以防止重复插入,但由于我们也处于休眠状态,因此 .save() 被称为 insert xxx RETURNING *

我似乎无法让插入规则在插入返回时很好地发挥作用。

CREATE TABLE test ( aaa int, bbb int);

insert into test VALUES(1, 2);

CREATE RULE "testRule1" AS ON INSERT TO  test
  WHERE EXISTS(SELECT 1 FROM test 
                WHERE (aaa, bbb)=(NEW.aaa, NEW.bbb))
  DO INSTEAD NOTHING;

如果我尝试仅使用 1 条条件规则插入

insert into test VALUES(1, 2);
ERROR:  cannot perform INSERT RETURNING on relation "test"
HINT:  You need an unconditional ON INSERT DO INSTEAD rule with a RETURNING clause.

CREATE RULE "testRule2" AS ON INSERT TO  test
  DO INSTEAD INSERT INTO test VALUES(new.*)
  RETURNING test.*;

如果我尝试同时使用条件规则和无条件规则插入

insert into test VALUES(1, 2);
ERROR:  infinite recursion detected in rules for relation "test"

我的设置无法实现吗?

【问题讨论】:

    标签: postgresql hibernate


    【解决方案1】:

    避免插入重复项的正确方法是将字段定义为UNIQUE(或PRIMARY KEY

    CREATE TABLE Test (
    aaa integer,
    bbb integer,
    val text, /* The reason why I added this field is explained later */
    UNIQUE (aaa,bbb)
    )
    

    如果元组已经存在,插入将失败并显示错误代码(从数据库接收错误代码是一件好事,正如我最近解释的 here)。

    如果出现错误是不可接受的,或者如果您想在单个 insert 中插入多条记录而不必关心哪个违反了 UNIQUE 约束,则正确的语法是使用 ON CONFLICT 子句.

    INSERT INTO Test values (1,1,'Some value')
    ON CONFLICT DO NOTHING
    

    基本上将插入具有唯一元组的第一条记录。即使查询本身尝试插入重复项,例如以下情况,这也是兼容的:

    INSERT INTO Test values (2,2,'Will be inserted'), (2,2,'Will not be inserted')
    ON CONFLICT DO NOTHING
    

    当然,这也将允许您在同一查询中使用 RETURNING 子句。

    【讨论】:

    • 对,但我想知道我是否可以使用 JPA 默认 CRUD 方法而不覆盖每个插入方法来添加额外的 ON CONFLICT DO NOTHING,这可能吗?还是我需要对所有插入使用原始查询?
    • 事实上,这是可能的。看看我的编辑,但请注意我不建议实施。您有一天会遇到一些限制,并付出高昂的代价才能切换回来。
    • 谢谢,我放弃了使 RULES 起作用,只是用 ON CONFLICT 子句覆盖所有插入语句。
    猜你喜欢
    • 1970-01-01
    • 2021-11-26
    • 2015-08-07
    • 2021-09-25
    • 2016-02-19
    • 2012-08-30
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    相关资源
    最近更新 更多