Ale*_*key 8 sql postgresql ruby-on-rails duplicates sql-insert
我正在开发一个使用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)
Run Code Online (Sandbox Code Playgroud)
这有两列:
现在如果我尝试插入一个带有重复的行some_other_id,它会失败(好)并且我在Postgres日志中得到以下输出:
Run Code Online (Sandbox Code Playgroud)ERROR: duplicate key value violates unique constraint "some_other_id_key"
问题是,我的应用程序尝试添加相同的ID两次是完全主线,并且我的日志被这个"错误"消息垃圾邮件,这会导致各种问题:文件占用大量磁盘空间,诊断会丢失噪音,Postgres必须丢弃diags以保持日志文件的大小限制等.
有谁知道我怎么做:
INSERT.INSERT.我听说过规则和触发器,但是我无法工作(虽然我不是Postgres专家).请注意,任何解决方案都需要使用Rails,它执行如下插入:
INSERT INTO test (some_other_id) VALUES (123) RETURNING id;
Run Code Online (Sandbox Code Playgroud)
Erw*_*ter 11
要避免重复键错误开始:
INSERT INTO test (some_other_id)
SELECT 123
WHERE NOT EXISTS (SELECT 1 FROM test WHERE some_other_id = 123)
RETURNING id;
Run Code Online (Sandbox Code Playgroud)
我假设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$
Run Code Online (Sandbox Code Playgroud)
呼叫:
SELECT f_my_insert(123);
Run Code Online (Sandbox Code Playgroud)
或者,默认为已存在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$
Run Code Online (Sandbox Code Playgroud)
同样,这为竞争条件留下了极小的机会.您可以以降低性能为代价来消除这种情况:
| 归档时间: |
|
| 查看次数: |
11093 次 |
| 最近记录: |