postgresql - Postgres : how to add unique identifier to table

标签 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;

通常它工作正常,但在高负载下,此功能有时会失败,并显示“重复键值违反唯一约束”myid_pkey”; 此函数在插入另一个表时从触发器调用,插入在事务内调用。隔离级别设置为 READ COMMITED,Debian Wheezy 上的 postgres 9.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 约束)。

为什么线程 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/

相关文章:

postgresql - Postgresql 的语音算法

postgresql - sql查询将字符串转换为数组,然后与某些条件进行比较

mysql - 在MySQL存储过程中创建动态查询?

c# - 如何知道在C#代码中具有TRY CATCH处理的存储过程中是否存在错误

django.db.utils.ProgrammingError : type "raster" does not exist

sql - 如何将 unix 时间戳转换为带时区的日期?

sql - 查询列出 SQL Server 存储过程以及每个过程的代码行

ios - 如何将 UITableView 的顶部粘贴到 UISearchBar 的底部?

ios - 自动布局(约束)与自动调整大小掩码(Springs & Struts)

Rails 中的 Mysql 约束数据库条目