一.bug始现
关联系统在上周五下班的时候反馈,调用我们系统的一个接口,返回报错。
因为是年前最后一个版本了,所以有bug一定要赶紧修。于是立刻查看什么情况。
查看到报错是唯一约束的错误,很明显是ID重复导致的。
代码很简单,就是接收关联系统传过来的对象,根据对象的五要素判断唯一,我们表里有就更新,没有就新增。代码中使用的saveOrUpdate进行操作。
二.问题排查
先大致查看了一下代码,确定了代码逻辑没有问题,那么问题只能是在ID的生成上了。
我们项目的ID生成是由数据库序列sequence自增生成的,插入数据时ID列为null,就自动通过序列自增进行填充。
于是首先查看一下当前的序列:select SEQ_CST_EQUITY_INFO_ID.currval from dual;
查出来序列值为1500,再查看一下当前表中的最大ID:select max(id) from CST_EQUITY_INFO,查到最大ID为1750。
定位到问题了,序列值比最大ID小,那么在插入时取到的序列值就是会有可能与已有ID存在冲突。但是为什么之前没有报错呢?查看表数据发现ID是不连续的,其中出现断层,在之前序列取到的都是断层前的值,于是不会冲突,直到取到断层处的值,出现了冲突。
仔细一看表中的那些数据,emmm,这不是我几个月之前提的脚本插进去的吗?!当时数据是从测试环境先清洗了一下之后,直接带着ID导入到生产环境了,但序列的值却没有动。
三.bug修复
找到了问题,那就赶紧修复。
因为生产权限比较严格,不能执行DDL,所以下面三种方法都不能用
--第一种 直接修改序列的步长,然后增长一次,再将步长修改回来 ALTER SEQUENCE SEQ_CST_EQUITY_INFO_ID INCREMENT BY 300; commit; select SEQ_CST_EQUITY_INFO_ID.nextval from dual; ALTER SEQUENCE SEQ_CST_EQUITY_INFO_ID INCREMENT BY 1; commit; --第二种 使用PL/SQL块 DECLARE v_nextval NUMBER; BEGIN FOR i IN 1..300 LOOP SELECT SEQ_CST_EQUITY_INFO_ID.NEXTVAL INTO v_nextval FROM dual; END LOOP; COMMIT; END; / --第三种 直接删除序列,以指定初始值的方式添加 DROP SEQUENCE SEQ_CST_EQUITY_INFO_ID; CREATE SEQUENCE SEQ_CST_EQUITY_INFO_ID START WITH 1800 -- 指定初始值 INCREMENT BY 1 -- 指定增量 NOCACHE; -- 可选,决定是否缓存序列值 SELECT SEQ_CST_EQUITY_INFO_ID.NEXTVAL FROM dual; -- 将返回 1800
难道只能一次一次的手动执行300次SELECT SEQ_CST_EQUITY_INFO_ID.NEXTVAL FROM dual吗!!!
当然不,于是我选择了下面这种方法
-- 两种写法 作用一样 SELECT HGC_CUSTOM.SEQ_CST_EQUITY_INFO_ID.NEXTVAL FROM dual CONNECT BY LEVEL <= 300; SELECT HGC_CUSTOM.SEQ_CST_EQUITY_INFO_ID.NEXTVAL FROM dual CONNECT BY ROWNUM <= 300;
OK,执行完毕,让关联方再次调用,正常了,问题解决。