PostgreSQL-重复唯一密钥
在我的表上,我有一个标记为md5的辅助唯一键。在插入之前,我检查MD5是否存在,如果不存在,请插入它,如下所示: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
-- 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:看起来他们得出了相同的结论:让数据库处理并发性。这实际上是我计划做的,只是不确定这是否是最好的选择。刚刚更新了我所有的函数来完成循环,现在运行良好=