關于金額的數(shù)據(jù)類型宗挥,以及元轉分分轉元之間這種轉換乌庶,以及元和分的比較,我相信很多人都踩過坑契耿。
反正我是踩過瞒大。
而且,昨天和今天又重重的踩了兩腳搪桂。
代付查詢接口透敌,支付中心給溢+響應的報文里盯滚,amount的單位是分,這無可厚非酗电,非常合理魄藕。
昨天,負責溢+代付的中威反映撵术,有一單雖然返回的是代付成功的狀態(tài)背率,但因校驗支付中心返回的代付金額與溢+存儲的代付金額不一致,而導致溢+未能更新代付單的狀態(tài)嫩与。
經(jīng)查寝姿,db里代付金額字段的數(shù)據(jù)類型是double,單位是元划滋,程序里對應的pojo也把代付金額的屬性設置為double饵筑。
出問題的那一單的代付金額是1049.11,支付中心響應的代付金額是104910古毛。顯然翻翩,這會致使溢+校驗代付金額失敗。
如下是賦值代碼:
responseModel.setAmount((int) (record.getPayMoney() * 100)); //元轉分
測試發(fā)現(xiàn)稻薇,Double的1049.11經(jīng)這么轉換后嫂冻,果然是104910。拍拍腦袋塞椎,這自然是double的數(shù)據(jù)精度的問題了桨仿。又進一步測試了幾個臨近的數(shù):1049.10→104909,1049.11→104910,1049.12→104911,并且1049.13可以正常轉換為104913
于是案狠,嘗試將代付金額的數(shù)據(jù)類型改為float服傍,經(jīng)測試,改為float是可以的骂铁。之前做結算系統(tǒng)時也遇到過類似問題吹零。由于手頭工作較多,這里不再繼續(xù)了解double和float的區(qū)別了拉庵。
--
走申請灿椅,上線!
--
到了今天下午钞支,溢+那邊又反映茫蛹,說又存在了3筆,支付中心返回了錯誤的代付金額烁挟。
/汗
其中一筆的代付金額是20.38婴洼,支付中心響應給溢+的值是2037。另外還有兩筆撼嗓,151.4→15139柬采;32.85→3284
不能再那么敷衍了欢唾。
同事說之前項目用的都是BigDecimal。我將信將疑警没,寫了個測試用例匈辱,來看看到底BigDecimal與Double/Float取值有哪些不同:
通過看測試數(shù)據(jù),發(fā)現(xiàn)杀迹,無論BigDecimal/Double/Float亡脸,其intValue()方法,返回的值都是整數(shù)部分树酪, 不會像Math.round()那樣做進行四舍五入浅碾。因為我上面貼出來的那條元轉分的語句,(int) (record.getPayMoney() * 100)等價于(record.getPayMoney() * 100).intValue()续语,所以垂谢,轉換得到的分就會出現(xiàn)因浮點型數(shù)據(jù)精度而導致的少1分的小概率情況。
那天有同事問我為什么interface的方法不用public修飾疮茄,我從OO角度跟他解釋了原因滥朱。 不琢磨,一些簡單的問題也搞不清力试。
而我今天徙邻,也同樣遭遇了他的那種情況。
最后畸裳,因為支付中心是從.net翻版的缰犁,我打開visualstudio,發(fā)現(xiàn)怖糊,.net給代付金額定義的類型也是decimal帅容。于是,果斷將代付金額的數(shù)據(jù)類型重構為BigDecimal伍伤。