Postgres:如何向表中添加唯一标识符

时间:2015-04-27 11:08:21

标签: postgresql stored-procedures constraints unique isolation-level

我有下表:

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;

一般情况下它工作正常,但在高负荷下,此功能有时会失败并且#34;重复键值违反了唯一约束" myid_pkey&#34 ;; 从另一个表上的insert上的触发器调用此函数,并在事务中调用插入。隔离级别设置为Debian Wheezy上的READ COMMITED,postgres 9.1。 我做错了什么?

1 个答案:

答案 0 :(得分:1)

我看到它是如何发生的。

  1. 两个进程(线程)使用相同的myid同时调用该函数。
  2. 两个线程都成功执行SELECT nid INTO ..查询,并看到 - 现在表中没有这样的myid
  3. 两个主题都进入IF NOT FOUND THEN
  4. 线程1执行INSERT INTO myid(myid)并提交没有错误的事务
  5. 线程2执行INSERT INTO myid(myid)并失败,因为表中已存在相同的myid值(PRIMARY KEY约束)。
  6. 为什么线程2在自己的事务中看到其他事务提交数据? 由于'不可重复读'现象,这可以通过READ COMMITTED隔离(http://www.postgresql.org/docs/9.2/static/transaction-iso.html)来实现。