oracle慎用char数据类型

昨天遇到了一个很奇怪的问题。一个很简单的功能,选择学习中心,然后选择课程,如果表中存在这个课程,就删除后重新添加(当然要是我写不会这么写的),主要是调用一个储存过程,如下

 

复制代码
代码
 1 CREATE OR REPLACE PROCEDURE OEMS.LCENTER_INPUTGRADEPOWER_M(
 2     v_LCenterCode    varchar2,
 3     v_UpbuildCourseId    in LCenter_InputGradePower.UpbuildCourseId%type,
 4     v_Status    char
 5 )
 6 AS
 7    v_lcentercodelist varchar2(4000):=v_LCenterCode;
 8    v_firstword char(8);
 9    v_length NUMBER:=0;
10 BEGIN
11      v_length := LENGTH(v_lcentercodelist);
12  WHILE v_length>0 LOOP
13     Popfirstword(v_lcentercodelist,v_firstword,v_length);
14 
15     Delete From LCenter_InputGradePower Where LCenterCode = v_firstword And UpbuildCourseId = v_UpbuildCourseId;
16     if (v_Status = '1'then
17         Insert Into LCenter_InputGradePower (LCenterCode,UpbuildCourseId) Values (v_firstword,v_UpbuildCourseId);
18     end if;
19 
20  END LOOP;        
21     
22 END;
23 /
24 
复制代码

 

代码非常简单,在测试服务器上也验证很正常。上线后,开始一段没问题,快下班的时候反馈有的学习中心选择不了课程,经过根据发现是发现执行上面的存储过程的时候出错。

验证代码:

exec LCENTER_INPUTGRADEPOWER_M('C052701',65279,1)

报错信息大概含义是 违反外键约束。我就仔细查看了了这个表中引用的约束

 

复制代码
代码
1 ALTER TABLE OEMS.LCENTER_INPUTGRADEPOWER ADD (
2   CONSTRAINT LCINPUTGRADEPO_R_UPBUILDCOU_ID 
3  FOREIGN KEY (UPBUILDCOURSEID) 
4  REFERENCES OEMS.JW_UPBUILDCOURSE (UPBUILDCOURSEID),
5   CONSTRAINT LCINPUTGRADEPOWER_R_LC_CODE 
6  FOREIGN KEY (LCENTERCODE) 
7  REFERENCES OEMS.JC_LCENTER (LCENTERCODE));
复制代码

 

这里用到了两个约束 ,一个是OEMS.JW_UPBUILDCOURSE 表的UPBUILDCOURSEID

一个是OEMS.JC_LCENTER的LCENTERCODE ,我单独查询这两个表'C052701'和65279都有值。这就很奇怪了,既然报错是约束,那肯定是插入的值和外键表中的值匹配不上啊。

尝试一:我试着单独向LCenter_InputGradePower 表插入数据,成功!

尝试二:调用存储过程执行,错误

看来问题还是在存储过程上,仔细查看存储过程,发现表jc_lcenter和UPBUILDCOURSEID字段的数据类型都是varchar2(8),但是存储过程内部采用的内部变量确实一个

 v_firstword char(8);

忽然想到传入的学习中心的编码是7位的C052701 这样在采用char数据类型存储的时候,不足8位的会补零的,但是对应的lcentercode的字段是varchar2(8)明显的

C0527010  与 C052701 是不同的。

原因找到了,那解决起来很简单。

把存储过程内部变量的v_firstword的数据类型更新为varchar2(8)就OK了。

验证通过。

 

教训:这个小小的问题从发现到解决花费了2-3个小时的时间,起先的排查点从程序---到发布---数据---最后才是数据库对象上,可谓是一个大圈。但是也给自己提了个醒,在oracle中尤其是存储过程和包中,尽量少用char类型,除非你很确定值不会变。但是这个也是很不保险的,因为这个问题当初的程序员可能得到的信息是学习中心的编码就是8位是不会变的,但是随着业务的发展,在目前就已经发生了变化,导致了问题。所以好的程序员一定要具有前瞻性,对可能出现问题的地方做到提前预防,提前处理。如果能预见到char数据类型可能带来的问题,那就能避免类似的问题发生。


posted @   天生我豺  阅读(3838)  评论(2编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述
点击右上角即可分享
微信分享提示