1 现象:问题描述
今年3月份左右A局点BOSS系统话单入库出现主键冲突,发现由于话单的ID号(CDRID)重复导致,对话单CDRID生成函数分析后发现话单CDRID生成机制如下
1. 从数据库中一个数据对象序列中取序列下个值(字符串类型)
2. 用atoi函数将该字符串类型的值转换成整型值,保存在整型变量cdrid中
3. 格式化该整型变量sprintf(szCdrId,"%03d%s%08d",eventid,szCurrTime,cdrid);其中cdrid就是从序列中取出的变量
但是现场发现当序列中值达到2*******时候出现CDRID重复!
2 关键过程:根本原因分析
仔细查看生成CDRID的函数,发现其中序列代码如下:
Create sequence
create sequence SEQ_CDRID
minvalue 1
maxvalue 999999999999
start with 1
increment by 1
cache 20
cycle;
生成CDRID函数处理逻辑如下:
循环处理若干条话单{
Getcdrid(char* szid)//从数据库序列对象中获取值
int cdrid=atoi(szid);
sprintf(szCdrId,"%d%s%d",eventid,szCurrTime,cdrid);
}
由于上面代码中cdrid是整型最大长度32位支持范围-2147483648~2147483647,但是序列的最大值定的却是9999999999,大大超过了int支持的整数范围,当序列值达到2147483649的时候,由于取出的值已经超过int取值范围,使用atoi函数时候 atoi("2147483649")= 2147483647,与前面当序列值取2147483647时候的cdrid冲突,加上序列中2147483647和2147483649这2个数的取值时间间隔小于1秒,导致sprintf里面的当前时间也一致,所以就形成了现场出现的szCdrId重复现象,导致话单入库失败;
另外atoi函数与实现系统有很大关系
在WIN32中atoi("2147483649")=-2147483647,atoi("2147483650")=-2147483646
在AIX中atoi("2147483649")= 2147483647,并且从2147483648开始不管值变得多大,atoi后始终是2147483647
设计人员在设计序列的时候没考虑程序中变量的数据类型字长和取值范围,导致字长越界,由于系统是AIX系统,导致在字长越界后出现重复值;
阅读(394) | 评论(0) | 转发(0) |