微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

sql – 禁止“重复键值违反唯一约束”错误

我正在开发一个使用Postgres作为其数据库的Rails 3应用程序.我有下面的表格:
Table "public.test"
    Column     |  Type   | Modifiers
---------------+---------+-----------
 id            | integer | not null
 some_other_id | integer |
Indexes:
    "test_pkey" PRIMARY KEY,btree (id)
    "some_other_id_key" UNIQUE CONSTRAINT,btree (some_other_id)

这有两列:

> id,这是主键(由rails自动创建)
> some_other_id,包含由另一个系统生成的密钥.这个id必须是唯一的,所以我在表中添加一个唯一的键约束.

现在如果我尝试插入一个带有重复some_other_id的行,它会失败(好)并且我在Postgres日志中得到以下输出

06001

问题是我的应用程序尝试添加相同的ID两次是完全主线,并且我的日志被这个“错误”消息垃圾邮件,这会导致各种问题:文件占用大量磁盘空间,诊断会丢失噪音,Postgres必须扔掉diags以保持日志文件的大小限制等.

有谁知道我怎么能:

>通过禁止有关此键的所有日志,或者通过在尝试执行INSERT的事务上指定某些内容来抑制日志.
>使用其他一些Postgres功能来发现重复的密钥,而不是尝试INSERT.我听说过规则和触发器,但我无法工作(虽然我不是Postgres专家).

请注意,任何解决方案都需要使用Rails,它执行如下插入:

INSERT INTO test (some_other_id) VALUES (123) RETURNING id;

解决方法

要避免重复键错误开始:
INSERT INTO test (some_other_id)
SELECT 123
WHERE  NOT EXISTS (SELECT 1 FROM test WHERE some_other_id = 123)
RETURNING id;

我假设id是一个自动获取其值的串行列.

这受到非常小的竞争条件(在SELECT和INSERT之间的时隙).但是可能发生的最糟糕的事情是你得到一个重复的密钥错误,这几乎不会发生,在你的情况下不应该是一个问题.

如果框架限制您使用正确语法的选项,则可以始终使用原始sql.

或者您可以为此目的创建UDF(用户定义的函数):

CREATE FUNCTION f_my_insert(int)
 RETURNS int LANGUAGE sql AS
$func$
INSERT INTO test (some_other_id)
SELECT $1
WHERE  NOT EXISTS (SELECT 1 FROM test WHERE some_other_id = $1)
RETURNING id;
$func$

呼叫:

SELECT f_my_insert(123);

或者,认为已存在的ID:

CREATE FUNCTION f_my_insert(int)
 RETURNS int LANGUAGE plpgsql AS
$func$
BEGIN;

RETURN QUERY
SELECT id FROM test WHERE some_other_id = $1;

IF NOT FOUND THEN
   INSERT INTO test (some_other_id)
   VALUES ($1)
   RETURNING id;
END IF;

END
$func$

同样,这为竞争条件留下了极小的机会.您可以以降低性能为代价来消除这种情况:

> Is SELECT or INSERT in a function prone to race conditions?

原文地址:https://www.jb51.cc/mssql/79013.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐