当前位置:网站首页>BigDecimal使用不当,造成P0事故!
BigDecimal使用不当,造成P0事故!
2022-07-19 20:25:00 【hello-java-maker】
今日推荐
减少 try-catch ,这样做才叫优雅!
让人上瘾的新一代开发神器,彻底告别Controller、Service、Dao等方法
SpringBoot实现人脸识别功能
相信我,使用 Stream 真的可以让代码更优雅!
全网最详细的线程池 ThreadPoolExecutor 解读!
利用多线程批量拆分 List 导入数据库,效率杠杠的!
文章来源:https://c1n.cn/MSqAy
目录
背景
事故
分析
总结
工具分享
背景
我们在使用金额计算或者展示金额的时候经常会使用 BigDecimal,也是涉及金额时非常推荐的一个类型。
BigDecimal 自身也提供了很多构造器方法,这些构造器方法使用不当可能会造成不必要的麻烦甚至是金额损失,从而引起事故资损。
事故
接下来我们看下收银台出的一起事故。
| 问题描述
收银台计算商品金额报错,导致订单无法支付。
| 事故级别
P0
| 事故过程
如下:
13:44,接到报警,订单支付失败,支付可用率降至 60%
13:50,迅速回滚上线代码,恢复正常
14:20,review 代码,预发布验证发现问题点
14:58,修改问题代码上线,线上恢复
| 故障原因
BigDecimal 在金额计算中丢失精度。
原因分析
首先我们先用一段代码复现问题根源,如下所示:
public static void main(String[] args) {
BigDecimal bigDecimal=new BigDecimal(88);
System.out.println(bigDecimal);
bigDecimal=new BigDecimal("8.8");
System.out.println(bigDecimal);
bigDecimal=new BigDecimal(8.8);
System.out.println(bigDecimal);
}
执行结果如下:
通过测试发现,当使用 double 或者 float 这些浮点数据类型时,会丢失精度,String、int 则不会,这是为什么呢?
我们点开构造器方法看下源码:
public static long doubleToLongBits(double value) {
long result = doubleToRawLongBits(value);
// Check for NaN based on values of bit fields, maximum
// exponent and nonzero significand.
if ( ((result & DoubleConsts.EXP_BIT_MASK) ==
DoubleConsts.EXP_BIT_MASK) &&
(result & DoubleConsts.SIGNIF_BIT_MASK) != 0L)
result = 0x7ff8000000000000L;
return result;
}
问题就处在 doubleToRawLongBits 这个方法上,在 jdk 中 double 类(float 与 int 对应)中提供了 double 与 long 转换,doubleToRawLongBits 就是将 double 转换为 long,这个方法是原始方法(底层不是 java 实现,是 c++ 实现的)。
double 之所以会出问题,是因为小数点转二进制丢失精度。
BigDecimal 在处理的时候把十进制小数扩大 N 倍让它在整数上进行计算,并保留相应的精度信息。
①float 和 double 类型,主要是为了科学计算和工程计算而设计的,之所以执行二进制浮点运算,是为了在广泛的数值范围上提供较为精确的快速近和计算。
②并没有提供完全精确的结果,所以不应该被用于精确的结果的场合。
③当浮点数达到一定大的数,就会自动使用科学计数法,这样的表示只是近似真实数而不等于真实数。
④当十进制小数位转换二进制的时候也会出现无限循环或者超过浮点数尾数的长度。
总结
所以,在涉及到精度计算的过程中,我们尽量使用 String 类型来进行转换。
最后,给大家推荐一个我的知识星球,现在加入,前 100 名,只需要 25 元即可,非常优惠。
边栏推荐
- Redis log: the killer mace of rapid recovery without fear of downtime
- Quick sort by hand
- 【实习】处理时间
- SAP mm transaction code Migo mobile type 561 error after saving -document number was already assigned
- LVGL 8.2 Slider
- 2022年最新内蒙古建筑安全员模拟题库及答案
- Code source du système vidéo court, séquence de chargement des fichiers principaux dans le projet uni app
- 【云图说】第248期 图解公网域名解析:轻松实现域名访问网站/邮箱
- Record the title of the 13th Landbridge cup embedded provincial competition
- Part of the second Shanxi Network Security Skills Competition (Enterprise Group) WP (V)
猜你喜欢
网络工程案例:CII公司的综合网络设计
马斯克称已将大脑上传到云端【系统或已开源】
適合送禮的藍牙耳機有哪些?2022藍牙耳機排行榜10强
Cannot make QOpenGLContext current in a different thread : PyQt多线程崩溃的解决方法
30 open source software most popular with IT companies
Come after me! Flutter realizes chasing animation
2019电赛复测测试题
SAP MM 事务代码MIGO 移动类型 561保存后报错-document number ### was already assigned
Sword finger offer 71: step jumping expansion problem
树的性质
随机推荐
Dest0g3 520迎新赛-web-EasyPHP
Spire.Office For Net 7.7.2 以及新闻
Arrays and pointers
mysql中数据表的基本操作很难嘛,由这个实验来带你从头走一遍
SAP mm transaction code Migo mobile type 561 error after saving -document number was already assigned
森马做LP的背后,“温州系”正跑步进入创投圈
stm32移植RT-Thread Nano实现finsh全步骤
Quick sort by hand
PostgreSQL 每张表的数据到达多少行就需要分区?
Skywalking全链路监控集群和动态部署
【云图说】第247期 初识华为云云解析服务
Summary on sorting and de duplication of sets
Source code of short video system, loading order of main files in uni app project
2019电赛复测测试题
Kingbasees SQL language reference manual of Jincang database (3.2. data type comparison rules)
赴港上市告吹后,土巴兔终止创业板IPO,创始人作出回应
R语言使用ggpubr包的gghistogram函数可视化分组箱图、添加分组均值、自定义分组色彩、添加轴须图(rug)、添加密度曲线、添加双y轴分别表示频率以及密度曲线的密度值
LVGL 8.2 Message box
Redis high availability: do you call this the principle of master-slave architecture data synchronization?
What is the difference between server bandwidth and home broadband?