我有下表:

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/

10-10 08:24