ORA-01438: value larger than specified precision allowed for this column & Could not synchronize database state with session
有段日子没做记录了,这段日子一直在排雷(前人埋下的隐患代码,或者直接说bug),今天这个雷让我排了将近大半天,因为是正式上线的系统,只能看后台日志,不能调试,打印出的异常信息不完整,种种的条件不充分,导致问题很难定位。标题上的两个异常,第一个一看就明白是插入的数值大于数据库字段长度,第二个多是因为Number类型的字段导致,比如精度不足。
我们的这次问题原因是程序员在做除法运算时没有对除数进行非零判断,导致计算出来的数值非法,插入数据库失败,请看代码:
public static void main(String[] args) { double a = 10; double b = 0; double c = 0; double m = a/c; double n = b/c; System.out.println(m); System.out.println(n); }
经过计算后,m和n的值分别是多少?没在实际开发中遇到的可能不知道,或者你有个好习惯不会出现这样的bug,请看结果:
被除数非零,除数为零做除法的结果是字符串“Infinity”,翻译成中文就是“无限”,你的中学数学老师可能说过; 被除数为零,除数为零做触发的结果是字符串“NaN”,即不是有效的数字。
就是这个“Infinity”花费了我一小天的时间才定位。下面详述问题定位的方法。
异常1:ORA-01438: value larger than specified precision allowed for this column 了解点数据库的打眼一看就知道插入的数值超过了表字段长度,但你知道是哪个表哪个字段吗?我不知道,于是网上查阅了下,Oracle数据库服务器在Linux上。
命令行登陆到数据库所在服务器,进入Oracle的安装目录,假设是/opt/oracle/ 进入到如下目录:/opt/oracle/admin/实例名/udump 中间的数据库实例名根据实际情况修改,udump目录下会有一堆的.trc文件,这些文件记录了所有操作当前数据库出现异常的堆栈信息。为了定位问题,我将该目录下的所有.trc文件都删除了(当然,删除之前把udump目录整个备份了),再进行一次系统的业务操作,查看一下udump目录,发现立刻生成一个新 的.trc文件,打开查看(内容片段):
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production With the Partitioning, Real Application Clusters, OLAP, Data Mining and Real Application Testing options ORACLE_HOME = /u01/app/oracle/product/10.2/db_1 System name: AIX Node name: gsdj1 Release: 1 Version: 6 Machine: 00CFD4644C00 Instance name: bjwd1 Redo thread mounted by this instance: 1 Oracle process number: 132 Unix process pid: 48300280, image: oracle@gsdj1 *** SERVICE NAME:(bjwd) 2014-03-28 16:48:05.683 *** SESSION ID:(2969.43961) 2014-03-28 16:48:05.683 *** 2014-03-28 16:48:05.683 ksedmp: internal or fatal error ORA-01438: value larger than specified precision allowed for this column Current SQL statement for this session: insert into CP_TEMP_STOCKTRAN (APPLY_ID, ALIEN, CER_TYPE, CER_NO, TRANS_AM, TRANS_AM_PR, TRANS_TYPE, TRANS_DATE, ENDORSOR, BLIC_TYPE, ALIEN_ID, ENDORSOR_ID, STOCKTRAN_ID) values (:1, :2, :3, :4, :5, :6, :7, :8, :9, :10, :11, :12, :13)
黄色背景红色字体的SQL就是罪魁祸首,这仅仅能定位发生问题的数据库表,字段还得自己排查。异常1让我定位到了这里,这时想起了异常2。
异常2: Could not synchronize database state with session
之前也搜索过这个异常,多数是由于Number类型的字段导致。冷静的思考一下,平常我们在做表设计时,会把文字类型的字段设置大一些,Number类型的精度也会根据实际业务进行设计,但往往Number类型的字段最容易出问题:
1、如果将非Number值插入该字段,比如字符串
2、如果插入的数值精度过多,如字段设计Number(10,2),也就是最大支持8为整数和两位小数,要插入34.121313就会失败
根据表名定位到hibernate的映射文件以及实体类,再从业务功能入口(一个action方法)搜索,终于定位到一个业务接口做了该实体类的保存代码,定位到了那个字段,定位到了做除法没有判断除数是否为0。