我有一个带有SERIAL ID的Postgres表。
id (serial) name age
插入通常来自于一个网络应用程序。
我手动插入了两个新记录,并将id设置为最大值(id)+1。****
在这两次插入之后,当网络应用程序再次插入2条记录时,它会显示重复键错误。
只有这两条记录会出现这种情况。之后一切正常。
问题是——为什么我的手动插入操作没有递增序列?
自动递增和序列是否不同?
我错过了什么吗?MySQL或任何其他SQL是否有相同的问题?
我有一个带有SERIAL ID的Postgres表。
id (serial) name age
插入通常来自于一个网络应用程序。
我手动插入了两个新记录,并将id设置为最大值(id)+1。****
在这两次插入之后,当网络应用程序再次插入2条记录时,它会显示重复键错误。
只有这两条记录会出现这种情况。之后一切正常。
问题是——为什么我的手动插入操作没有递增序列?
自动递增和序列是否不同?
我错过了什么吗?MySQL或任何其他SQL是否有相同的问题?
serial
或者bigserial
列时,PostgreSQL实际上会做三件事情:
int
或者bigint
列。nextval()
。serial
列的值(或者显式地将其值指定为DEFAULT
)时,nextval
将会调用序列来:
serial
列提供非默认值,则序列不会被更新,而nextval
可以返回已使用您的serial
列的值。因此,如果您这样做,您将不得不通过调用nextval
或setval
来手动修复序列。serial
列中出现间隔是可以预期的,即使没有并发问题,也不要使用max(id) + 1
,这不是一个好主意。serial
或bigserial
,最好让PostgreSQL为您分配值,并假装它们是一些以特定顺序出现的不透明数字:不要自己分配它们,也不要假设任何关于它们的东西,除了唯一性。我认为这个经验法则适用于所有数据库。
我不确定MySQL的auto_increment
如何与所有不同类型的数据库一起使用,但也许精细手册可以帮助。
serial
和auto_increment
的值留给数据库,不要对它们进行任何更改。如果让数据库分配serial
值,则序列将会更新,一切都会很好;如果手动分配值,则必须手动更新序列。 - mu is too short如果您想向具有“序列”列的表中插入记录 - 只需从查询中省略它 - 它将自动生成。
或者您可以使用类似以下内容的语句插入其默认值:
insert into your_table(id, val)
values (default, '123');
insert into your_table(id, val)
values (nextval(pg_get_serial_sequence('your_table','id')), '123');
我手动插入了两条新记录,并将id设置为max(id)+1*。*
这种方法在任何数据库中都是完全错误的,只有在MySQL中因为幸运的原因才能够工作。
如果同时有两个连接运行此操作,则会得到相同的ID。只有在锁定表以防止并发读取的情况下,才能可靠地使用此方法,以便只有一个连接可以获取ID。
此外,这种方法效率极低。
这就是为什么序列存在的原因,因为它们可以在并发插入时可靠地获取ID。
请使用以下方法:
INSERT INTO my_table(data1, data2) VALUES ('a','b') RETURNING id;
或者:
INSERT INTO my_table(id, data1, data2) VALUES (DEFAULT, 'a','b') RETURNING id;
DEFAULT
是一个特殊的占位符,它告诉数据库从表定义中获取该列的默认值。默认值为nextval('my_table_id_seq')
,因此下一个序列值将被插入。