有段日子沒做記錄了,這段日子一直在排雷(前人埋下的隱患代碼,或者直接說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。