我有下表:
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失败的情况;
此函数在另一个表上的insert时从触发器调用,在事务中调用insert。隔离级别设置为READ committed,postgres 9.1 on Debian喘息。
我做错什么了?
最佳答案
我明白了事情的来龙去脉。
两个进程(线程)使用相同的myid
同时调用该函数。
两个线程都成功地执行了SELECT nid INTO ..
查询,现在表中没有这样的myid
了。
两个线程都进入IF NOT FOUND THEN
线程1执行INSERT INTO myid(myid)
并提交无错误的事务
线程2执行INSERT INTO myid(myid)
并失败,因为表(主键约束)中已经存在同样的myid
值。
为什么线程2在自己的事务中看到其他事务提交的数据?
因为存在“不可重复读取”现象,这可能与读取提交隔离(http://www.postgresql.org/docs/9.2/static/transaction-iso.html)有关。
关于postgresql - Postgres:如何向表添加唯一标识符,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29894068/