场景描述
在最近的工作中,遇到了一个自增队列使用的问题,记录一下解决过程和方案。
针对某个业务表 (user),包含三列:id 、code、name,其中id列为主键列,使用自增序列方式,目前存在业务功能(用户维护1),在用户维护新增用户保存时,主键通过自增序列自动生成 ,写法如下:
(insert into user(code,name) values('admin','系统管理员') returning id;
--通过自增序列生成id,并且使用returning id 将生成的主键返回
现在需要使用某框架做一个新的用户维护功能(用户维护2),并且两套功能要同时使用,由于框架限制,新增的数据的主键需要在插入数据(insert)之前就得到,这样就无法使用如上SQL来处理了。
因为两个功能要同时使用,并且用户维护1功能逻辑不能改变,两套功能新增的user数据主键不能冲突。
解决过程
第一次尝试
在用户维护2中,使用序号提前得到下一个序列(假如得到的结果10):
SELECT ,MAX(id)+1 FROM user;
然后在保存时,将得到的下一个序列值插入到数据库中:
insert into user(id,code,name) values(10,'code11','name11')
新功能测试好使,但是在一起使用时,出现了问题:在用户维护1中,新增的数据,自增序列生成的主键值,也会生成10,结果与用户维护2新增的数据出现主键冲突。
问题分析:貌似如下sql并没用把序列的占用值更新,所以10仍然可用。
正确方案
在获取主键值时,使用如下sql,在获取下一个主键时,及时更新自增序列的当前值,这样用户维护1新增数据时,才会跳过已经获取到的主键,避免主键冲突:
SELECT setval('自增序列名',nextval('自增序列名'),true) FROM user;
注:本来打算使用参考文档中的如下写法来获取主键,但是貌似如下写法也并未更新自增序列的最大号
SELECT setval('自增序列名',MAX(id)+1,true) FROM user;