2

在我的桌子上,我有一个标记为 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。我最终遇到的情况是:

应用程序 1:看到 MD5 不存在

应用 2:将此 MD5 插入表中

应用程序 1:现在将 MD5 插入到表中,因为它认为它不存在,但由于在它看到它不存在后立即出现错误,应用程序 2 插入了它。

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

我可以在插入时捕捉到错误吗?如果可以,然后选择 domain_id?

提前致谢!


这似乎也包含在插入中,在 PostgreSQL 中重复更新?

4

1 回答 1

2

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

像这样的东西:

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

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

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

于 2011-07-21T06:03:43.637 回答