【问题标题】:PostgreSQL - Duplicate Unique KeyPostgreSQL - 重复的唯一键
【发布时间】:2011-07-21 05:38:02
【问题描述】:

在我的桌子上,我有一个标记为 md5 的辅助唯一键。插入前我先检查一下MD5是否存在,如果没有就插入,如下图:

-- Attempt to find this item
SELECT INTO oResults (SELECT domain_id FROM db.domains WHERE "md5"=oMD5);

IF (oResults IS NULL) THEN

    -- Attempt to find this domain
    INSERT INTO db.domains ("md5", "domain", "inserted") 
        VALUES (oMD5, oDomain, now());

    RETURN currval('db.domains_seq');

  END IF;

这对于单线程插入非常有用,我的问题是当我有两个外部应用程序同时调用我的函数时恰好具有相同的 MD5。我最终会遇到以下情况:

App 1:发现 MD5 不存在

应用 2:将此 MD5 插入表中

App 1:进入现在将 MD5 插入到表中,因为它认为它不存在,但得到一个错误,因为在它看到它不存在之后,App 2 插入了它。

有没有更有效的方法来做到这一点?

我能否在插入时发现错误,如果是,则选择 domain_id?

提前致谢!


Insert, on duplicate update in PostgreSQL? 似乎也涵盖了这一点

【问题讨论】:

    标签: postgresql concurrency unique-key


    【解决方案1】:

    您可以继续尝试插入 MD5 并捕获错误,如果您收到“违反唯一约束”错误,则忽略它并继续操作,如果您遇到其他错误,则退出。这样一来,您将重复检查直接推送到数据库,您的竞争条件就会消失。

    类似这样的:

    • 尝试插入 MD5 值。
      • 如果您收到唯一的违规错误,请忽略它并继续。
      • 如果您遇到其他错误,请退出并投诉。
      • 如果您没有收到错误,请继续。
    • 使用SELECT INTO oResults (SELECT domain_id FROM db.domains WHERE "md5"=oMD5) 提取domain_id

    可能会有一点性能影响,但“正确但有点慢”比“快但坏”要好。

    最终,您可能会遇到更多成功插入的异常。然后您可以尝试在表中插入引用(通过外键)您的db.domains 并在那里捕获 FK 违规。如果您有 FK 违规,请在 db.domains 上执行旧的“插入并忽略唯一违规”,然后重试导致 FK 违规的插入。这是相同的基本思想,只是选择哪一个可能引发最少的异常并继续下去。

    【讨论】:

    • 那是我的下一个,只是研究如何找到错误。谢谢。
    • @Anthony:我添加了一些更新,当您的 db.domains 接近覆盖您将要处理的所有域时,它可能会有所帮助。
    • stackoverflow.com/questions/1109061/… 似乎也涵盖了我同样的问题
    • @Anthony:看起来他们得出了相同的结论:让数据库处理并发。
    • 这实际上是我打算做的,只是不确定它是否是最佳选择。刚刚更新了我所有的功能来执行循环并且现在工作良好 =)
    猜你喜欢
    • 2011-05-25
    • 1970-01-01
    • 2016-09-28
    • 2011-10-17
    • 1970-01-01
    • 2014-08-18
    • 1970-01-01
    • 2016-10-24
    相关资源
    最近更新 更多