pg在实现自增id的时候,主要有两种方式,方法1是将id设置为SERIAL类型。方法2是新建一个序列,设置id的默认值为序列的NEXT值。
方法1:sql
CREATE TABLE test1 ( id SERIAL primary key )
方法2:数据库
CREATE TABLE test2 ( id primary key ); CREATE SEQUENCE test2_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE NO MAXVALUE CACHE 1; alter table test2 alter column id set default nextval('test2_id_seq');
方法1较简单,其实他的实现方式,是数据库自动建立了一个序列,而后将id的默认值设置为这个序列的next值。能够看出方法1和方法2都是经过序列实现了id的自增。那方法1和方法2的区别呢?测试
首先,方法1较简单。可是方法2更加灵活,可以本身设定起始值,最大值,最小值,步长等(固然方法1也能够再用命令改系统生成的序列,那为何不直接用方法2呢?)。还有就是当删除方法1创建的表时,对应的序列会自动删除,而方法2不会。日志
有一张表A,服务1有一个接口在A中插入数据。因为某种缘由服务2也有一张这样的表B,须要保持这两张表的数据一致。以前是手动将表B的数据添加到表A中,如今进行了开发,自动调用接口进行同步。在测试环境上测试没有问题了。上线,当使用的时候,发现没有插入进去。
下面为分析的过程:code
**1.看报错日志 **
报错日志上的信息是Sequelize Validation error。Sequelize是一种orm,开始怀疑是sequelize进行了错误的验证。将插入前的sequelize验证取消,上线后发现仍是不行。orm
2.加上sql日志
怀疑是sql语句有问题,将sequelize转化出的sql语句打印在日志中。发现是一句最简单的插入语句。将其复制,直接在数据库执行,发现报错了。索引
3.查看数据库报错信息
简要报错信息上写的是惟一索引冲突。表中确实是有惟一索引。经过sql查询到,表中并无与其冲突的记录。查看详细的报错信息,信息上写着id:xxx已经存在。看了下这个id确实是存在了。接口
4.id的生成方式
sql语句中并无指定id,id是经过自增序列获取的。那自增序列为何不对呢?原来当插入数据时,指定了id的值时,id序列不会变化,不会取出下一个。好比一张表,id默认值是序列的next,步长是1。当表中的最大的id为100,序列的next值101时,若是执行了insert into table (id,name) values(101,'xixi'),那么序列的next值不会变化,仍是101。此时执行insert into table (name) values ('haha'),因为id为101的记录已经存在了,因此会报错:id上的惟一索引冲突。开发
5.产生bug的缘由
线上有一次批量同步数据,是直接将sql复制过来(带id),执行sql插入数据。形成了表中的最大id和id序列的当前值不一致。调用接口插入的时候是不带id的,取得是id序列的next,而next的值,表中有记录的id与之相同,形成了id惟一索引冲突。而测试环境中,没有进行过带id的数据同步,同步数据的时候,id序列同步变化,因此没有这种问题。同步
6.解决办法
解决办法就是手动设置下序列的当前值为表中id的最大值。sql语句为:
SELECT setval('序列名', (SELECT max(id) FROM 表名));