我有下表:
CREATE TABLE myid
(
nid bigserial NOT NULL,
myid character varying NOT NULL,
CONSTRAINT myid_pkey PRIMARY KEY (myid )
)
现在,我想使用以下函数向该表添加记录:
CREATE FUNCTION getmyid(_myid character varying)
RETURNS bigint AS
$BODY$ --version 1.1 2015-03-04 08:16
DECLARE
p_nid bigint;
BEGIN
SELECT nid INTO p_nid FROM myid WHERE myid=_myid FOR UPDATE;
IF NOT FOUND THEN
INSERT INTO myid(myid) VALUES(_myid) RETURNING nid INTO p_nid;
END IF;
RETURN p_nid;
END;$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
通常它工作正常,但在高负载下,此功能有时会失败,并显示“重复键值违反唯一约束”myid_pkey”; 此函数在插入另一个表时从触发器调用,插入在事务内调用。隔离级别设置为 READ COMMITED,Debian Wheezy 上的 postgres 9.1。 我做错了什么?
最佳答案
我通过以下方式了解它是如何发生的。
- 两个进程(线程)使用相同的
myid
同时调用该函数。 - 两个线程都成功地执行了
SELECT nid INTO ..
查询,并且看到- 现在表中没有这样的myid
。 - 两个线程都进入
IF NOT FOUND THEN
- 线程 1 执行
INSERT INTO myid(myid)
并无错误地提交事务 - 线程 2 执行
INSERT INTO myid(myid)
并失败,因为表中已存在相同的myid
值(PRIMARY KEY 约束)。
为什么线程 2 在自己的事务中看到其他事务提交的数据? 由于“不可重复读取”现象,这可以通过 READ COMMITTED 隔离 ( http://www.postgresql.org/docs/9.2/static/transaction-iso.html ) 实现。
关于postgresql - Postgres : how to add unique identifier to table,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29894068/