多么痛的领悟---关于RMB数据类型导致的元转分分转元的bug

关于金额的数据类型,以及元转分分转元之间这种转换,以元和分的比较,我相信很多人都踩过坑。

反正我是踩过。

而且,昨天和今天又重重的踩了两脚。

代付查询接口,支付中心给溢+响应的报文里,amount的单位是分,这无可厚非,非常合理。

昨天,负责溢+代付的中威反映,有一单虽然返回的是代付成功的状态,但因校验支付中心返回的代付金额与溢+存储的代付金额不一致,而导致溢+未能更新代付单的状态。

经查,db里代付金额字段的数据类型是double,单位是元,程序里对应的pojo也把代付金额的属性设置为double。

出问题的那一单的代付金额是1049.11,支付中心响应的代付金额是104910。显然,这会致使溢+校验代付金额失败。

如下是赋值代码:
responseModel.setAmount((int) (record.getPayMoney() * 100)); //元转分

测试发现,Double的1049.11经这么转换后,果然是104910。拍拍脑袋,这自然是double的数据精度的问题了。又进一步测试了几个临近的数:1049.10→104909,1049.11→104910,1049.12→104911,并且1049.13可以正常转换为104913
于是,尝试将代付金额的数据类型改为float,经测试,改为float是可以的。
之前做结算系统时也遇到过类似问题。由于手头工作较多,这里不再继续了解double和float的区别了。

走申请,上线!

到了今天下午,溢+那边又反映,说又存在了3笔,支付中心返回了错误的代付金额。

/汗

其中一笔的代付金额是20.38,支付中心响应给溢+的值是2037。另外还有两笔,151.4→15139;32.85→3284

不能再那么敷衍了。

同事说之前项目用的都是BigDecimal。我将信将疑,写了个测试用例,来看看到底BigDecimal与Double/Float取值有哪些不同:

通过看测试数据,发现,无论BigDecimal/Double/Float,其intValue()方法,返回的值都是整数部分, 不会像Math.round()那样做进行四舍五入。因为我上面贴出来的那条元转分的语句,(int) (record.getPayMoney() * 100)等价于(record.getPayMoney() * 100).intValue(),所以,转换得到的分就会出现因浮点型数据精度而导致的少1分的小概率情况。

那天有同事问我为什么interface的方法不用public修饰,我从OO角度跟他解释了原因。 不琢磨,一些简单的问题也搞不清。而我今天,也同样遭遇了他的那种情况。

最后,因为支付中心是从.net翻版的,我打开visualstudio,发现,.net给代付金额定义的类型也是decimal。
于是,果断将代付金额的数据类型重构为BigDecimal。

时间: 09-13

多么痛的领悟---关于RMB数据类型导致的元转分分转元的bug的相关文章

Bellon(多么痛的领悟)

尼玛  我今天刚刚知道什么是负权回路 任意相连的无向图之间都是回路!!! 囧了一天了,算是看出来了,渣比 A====B 则A能到B且B能到A,这就是一个回路. Bellon(多么痛的领悟),布布扣,bubuko.com

【机房收费系统】多么痛的领悟

这次机房收费系统,是所有的项目中,自己完成的最不满意的了. 时间之长,效率之慢.一开始,就感觉无从下手,但总会相信自己能慢慢的进入状态.终于有机会自己练练手了,也自认为之前自己设计模式学的还不错,也终于有机会能自己想想设计模式了.该是一件多么帅的事.拖了这么久,到现在只用上了外观 抽象工厂 模板 个人版就这么结束了.真心不想再拖一天了. 话说,并不觉得自己敲代码会比别人差多少.一开始敲完三层,又开始画图.还是一头的雾水.设计数据库,终于有了一点自己的想法也重温了之前学习的数据库原理,还是比较欣慰

多么痛的领悟----(码农的低级错误)

(2017-7-23) 问题描述: 页面url请求发出后,显示404; 控制台debug: p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Monaco } [DEBUG] Last-Modified value for [/page/index] is: -1 [org.springframework.web.servlet.DispatcherServlet]- [DEBUG] Null ModelAndView returned t

数据倾斜是多么痛?spark作业调优秘籍

目录视图 摘要视图 订阅 [观点]物联网与大数据将助推工业应用的崛起,你认同么?      CSDN日报20170703--<从高考到程序员--我一直在寻找答案>      [直播]探究Linux的总线.设备.驱动模型! 数据倾斜是多么痛?spark作业调优秘籍 2017-06-27 13:28 39人阅读 评论(0) 收藏 举报  分类: Spark(124)  原文:https://mp.weixin.qq.com/s?__biz=MzI5OTAwMTM1MQ==&mid=2456

mysql/Java服务端对emoji的支持

如果UTF8字符集且是Java服务器的话,当存储含有emoji表情时,会抛出类似如下异常: java.sql.SQLException: Incorrect string value: '\xF0\x9F\x92\x94' for column 'name' at row 1       at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)       at com.mysql.jdbc.MysqlIO.checkEr

《用Python做HTTP接口测试》学习感悟

机缘巧合之下,报名参加了阿奎老师发布在"好班长"的课程<用Python做HTTP接口测试>,报名费:15rmb,不到一杯咖啡钱,目前为止的状态:坚定不移的跟下去,自学+课程模式每天一小时! 1.学习初衷 打算学习Python,这个想法开始于2017年,和在网络上遇到的绝大多数测试人员不同,我的工作单位是一个大型国企,虽然从事软件测试工作已经有四年,可事实上,无论是测试理论还是实际项目经验,都处于一种停滞不前的状态,作为一个有理想的测试猿(害羞脸),这样的工作状态让人心酸,因

Redis 集群的合纵与连横

之前一篇写了关于 Redis 的性能,这篇就写写我认为比性能更重要的扩展性方面的主题. 如果再给我一次回到好几年前的机会,对于使用 Redis 我一开始就要好好考虑将来的扩展问题.就像我们做数据库分库分表,一旦决策了分库分表,通常一次就会分到位,比如搞上 8 或 16 个库,每个库再分 256 或 1024 个表.不管将来业务再怎么发展,基本这个量级的分片都足够应对,而且底层库可以做成逻辑的,扛不住时再换成物理的,对应用方完全透明,没有数据迁移的烦恼. 而 Redis 其实也提供了类似的逻辑库概

盘点几种喜好“嘲讽”老罗的人

锤子手机最终扛不住了,近期,锤子科技官方公布声明称,自10月30日上午10点起,对锤子Smartisan T1的售价进行调整,将以1980元(3G版16GB内存)的起步价格在天猫官方旗舰店现货发售.此前,锤子T1手机的3个版本号价格分别为:3G版16G,3000元:3G版32G,3150元:4G版32G,3500元.而此次下调后,这3个版本号的价格分别为:1980元.2080元.2480元,降幅分别为34%.34%和29%. 对这件事,媒体和业界大多持嘲讽的态度,这从非常多评论的标题你就能够看出

高性能Web服务之nginx应用详解

一.Nginx特性 * *模块化,目前只能将模块编译进Nginx,暂时不支持动态装卸模块.(httpd优势) * *可靠性,一个主进程(master)控制多个工作进程(worker),工作进程响应用户多个请求(httpd劣势) * *低内存消耗,(httpd劣势) * *支持热部署,(httpd相同) * *支持事件驱动I/O,AI/O,支持mmap(httpd2.4才算支持event,劣势) 二.Nginx基本架构 Nginx由一个master进程生成多个worker进程,每个worker进程