PostgreSQL-重复唯一密钥

PostgreSQL-重复唯一密钥,postgresql,concurrency,unique-key,Postgresql,Concurrency,Unique Key,在我的表上,我有一个标记为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的辅助唯一键。在插入之前,我检查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插入到表中”,因为它认为MD5不存在,但得到一个错误,因为在它看到MD5不存在后,应用2立即将其插入

有没有更有效的方法

我是否可以捕获插入时的错误,如果是,请选择域id

提前谢谢


这似乎也在

中讨论过,您可以继续尝试插入MD5并捕获错误,如果您遇到唯一的约束冲突错误,则忽略它并继续,如果遇到其他错误,则退出。这样,您就可以将重复检查直接下推到数据库中,您的竞争条件就消失了

大概是这样的:

尝试插入MD5值。 如果您得到一个唯一的违规错误,则忽略它并继续。 如果你遇到了其他错误,就跳出去抱怨。 如果没有出现错误,请继续。 执行SELECT INTO oResults从db.domains(其中md5=oMD5)中选择域\u id以提取域\u id。 可能会有一点性能上的打击,但正确和一点慢比快但坏


最终,您可能会遇到比成功插入更多的异常。然后,您可以尝试通过一个外键在表中插入对db.domains的引用,并在其中捕获FK冲突。如果存在FK冲突,请执行旧的插入并忽略db.domains上的唯一冲突,然后重试导致FK冲突的插入。这是相同的基本想法,只是选择哪一个可能抛出最少的异常,然后继续。

这是我的下一个想法,只是要研究如何找到错误。谢谢。@Anthony:我添加了一个小更新,当您的db.domains接近覆盖您将要处理的所有域时,可能会有所帮助。似乎也涵盖了我的同样issue@Anthony:看起来他们得出了相同的结论:让数据库处理并发性。这实际上是我计划做的,只是不确定这是否是最好的选择。刚刚更新了我所有的函数来完成循环,现在运行良好=