2011-03-30 44 views
1

如何在发生错误时抑制此表中的'id'增量?错误增加

db=> CREATE TABLE test (id serial primary key, info text, UNIQUE(info)); 
NOTICE: CREATE TABLE will create implicit sequence "test_id_seq" for serial column "test.id" 
NOTICE: CREATE TABLE/PRIMARY KEY will create implicit index "test_pkey" for table "test" 
NOTICE: CREATE TABLE/UNIQUE will create implicit index "test_info_key" for table "test" 
CREATE TABLE 

db=> INSERT INTO test (info) VALUES ('hello') ; 
INSERT 0 1 

db=> INSERT INTO test (info) VALUES ('hello') ; 
ERROR: duplicate key violates unique constraint "test_info_key" 

db=> INSERT INTO test (info) VALUES ('hello') ; 
ERROR: duplicate key violates unique constraint "test_info_key" 

db=> INSERT INTO test (info) VALUES ('goodbye') ; 
INSERT 0 1 

db=> SELECT * from test; SELECT last_value from test_id_seq; 

id | info 
----+--------- 
    1 | hello 
    4 | goodbye 
(2 rows) 

last_value 
------------ 
      4 
(1 row) 
+0

你能解释为什么这是你的问题? – intgr 2011-03-30 20:04:31

+0

当我将一个较小的远程数据库转储到一个更大的主数据库中时,我注意到了id序列中的跳转。有几个远程数据库,我需要达到高潮。原来我省略了表格布局中的'id',并仅依靠 – 2011-03-30 21:10:45

+0

...原来我在表布局中省略了'id',并仅依赖于UNIQUE键值。这可防止在再次插入相同行时创建重复行。 – 2011-03-30 21:18:57

回答

0

我想通了。

我需要在我的INSERT语句中编写一个包装函数。

数据库一般每次只有一个用户,所以'下一个ID'竞争条件很少见。我担心的是,当我的(未提到的)'从远程数据库表中'拉行'将尝试重新插入不断增长的远程数据库表到主数据库表中。我显示的是行ID,我不希望用户看到编号中缺失的数据。

反正这里是我的解决方案:

CREATE FUNCTION testInsert (test.info%TYPE) RETURNS void AS ' 
BEGIN 
    PERFORM info FROM test WHERE info=$1; 
    IF NOT FOUND THEN 
    INSERT INTO test (info) VALUES ($1); 
    END IF; 
END;' LANGUAGE plpgsql; 
5

不能抑制这一点 - 并没有什么错在你的ID值的差距。

主键是一个完全没有意义的值,仅用于唯一标识表中的一行。

你不能依靠ID来永远没有任何差距 - 只要想想如果你删除一行就会发生什么。

简单地忽略它 - 没有什么是错

编辑
只是想提一提,这种行为也明确手册中规定:

为了避免阻断获得大量并发交易从相同的序列,nextval操作永远不会回滚

http://www.postgresql.org/docs/current/static/functions-sequence.html
(滚动到底)

+0

感谢您的澄清。我认为INSERT语句是一个原子事务,在成功插入时会增加。 – 2011-03-30 21:25:20

+0

编号的差距对我的代码是有益的。 – 2011-03-30 21:26:13

+0

@John Wasinger:INSERT本身**是**原子的,只有序列号的生成是非事务性的,因此不是原子的(btw:这在所有支持序列的DBMS中都是相同的) – 2011-03-31 06:53:06

1

想象不同的事务去插入。事务A得到id = 1事务B得到id = 2。事务B提交。交易A回滚。现在我们该怎么办?我们如何回滚A的顺序而不影响B或以后的交易?

+0

+1非常好说明序列不回滚的原因之一,以及为什么不应该坚持/依赖“无间隙”序列。 – 2011-03-31 19:58:40