记序列sequence疏忽带来的线上bug

一.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,执行完毕,让关联方再次调用,正常了,问题解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值