mysql数据精度丢失问题深入探讨
不要盲目的说float和double精度可能发生丢失,而是说在存取时因为精度不一致会发生丢失,当然这里的丢失指的是扩展或者截断了,丢失了原有的精度。decimal是好,但不是说不会发生任何精度丢失。如果问题看得不深入,总会以偏概全。
我们知道,mysql存储小数可以使用float、double、decimal等。这些类型存储的小数精度都比较高。我们平时应用最多的就是两位小数点,所以,这些类型都是可以满足的。
那么数据精度丢失是如何表现的呢?到底是什么原因呢?
当我们不知道原因的时候,总会认为到处都是问题,找不到关键点。在应用的时候,总是不踏实,唯唯诺诺的。搞清楚缘由,找到问题的关键点,然后加以深入理解,方可给自己一个定心丸。
精度变化不管是哪种类型,都会发生。网上言传float、double精度可能丢失,decimal精度不会丢失,所以建议decimal来存储金额值。但是,没有指明确切缘由,只是大概是这么回事,其实离真相还差得远。
在mysql中,我们用【小数数据类型(总长度,小数点长度)】来表示小数的总长度和小数点后面的长度,如decimal(m,n)。n就是小数点后面的 数字个数。float(m,n)、double(m,n)含义差不多,都是定义长度和精度的。既然都定义了精度,为什么还会发生所谓的精度丢失问题呢?
查阅网上的说法,要么是没有设置精度位数,要么就是设置的精度和存储时的精度不一致,要么就是mysql存的,用其他数据库引擎查询。基本是这三类可以概括各种情况。
这三种有什么共性和差异性呢?如果能够将这三种情况抽象为一个共同的模型,我们就找到了精度丢失问题的关键。而不是盲人摸象般的局部就事论事,以偏概全了。
没有设置精度就是使用默认的精度,此时的策略就是,尽可能保证精度,因此一般使用最高精度存储数据的。如果设置数据类型指定了精度,那么存储数据时就按照设置的精度来存储。第三种暂时不讨论,先把前面两种说完。
假设默认精度为6个小数位或设置为6位,我们存储小数一般是:2 1.1 2.11 32.214 41.4513 5.21452 6.214522 7.1421457,这里有8个不同的小数位的数,在存储到数据库时会发生什么问题?
使用默认精度,数据库用6位来存储。所以前面6个数字,精度都不够6位。当然,存储时如果是float和double,那么会尽可能以近似的值存储,以保 证精度。所以,结果可能是:2.000001 2.110005 32.213999 41.451301 5.214519。如果用的是decimal,则结果是:2 1.1 2.11 32.214 41.4513 5.21452 。从这个结果可以看到,decimal的存储结果没有精度丢失问题。因为decimal内部以字符形式存储小数,属于准确存储。而float和 double等则属于浮点数数字存储,所以没有办法做到准确,只能尽可能近似。这也是大家选用decimal的原因,也认为decimal精度不会丢失的 原因。
这个结果对,但不全对。数据的精度丢失发生在存储和获取这一瞬间。所以,存储和获取这两个方面也就是精度发生变化的时刻。这里的精度丢失发生在存储时。这里举例使用6位精度来兼容不同的精度数值。还有6位精度和大于6位精度的值我们还没有讨论,现在来讨论一下。
是不是6位精度值存入6位精度类型精度就不会丢失了呢?必须不能丢失。如果丢失了,谁还敢用这样的类型呢?这样的类型还有什么意义呢?所以,6.214522存入6位小数的float和double是不会丢失小数精度的,取出来的数还是6.214522。
也就是说,一个小数存入相同的精度的数据类型时,精度是不会丢失的。
另一种情况,当7或更多位精度的数字存入6位精度类型字段时,会发生什么?结果会发生四舍五入。四舍五入的结果就是匹配字段的数据类型的精度长度。此时精 度也会丢失。不管内部如何处理,我们得到的数据是经过四舍五入的。但是有一点可以确定,我们在读取取舍后的数字时,是固定的。虽然浮点数存储的不是确切的 数值,但是在你指定的精度长度条件下,存取都是确定的一个数值。而发生精度变化的就是数值的精度和字段的精度长度不匹配,从而发生数值扩展精度和截断精度 问题,这也就是浮点数精度不准确的问题。
有人说,用浮点数存储在查询时会发生无法匹配的问题。例如,存入的数据为15.21,查询的时候用15.21竟然匹配不到15.21这条记录。然而这是个 人没有理解数据库浮点数处理问题。我反正是可以准确匹配查询的。在设置两位精度的字段数据类型时,存取数据得到的都是两位精度的值,在查询时用两位的数值 自然也是可以匹配到的。匹配不到的情况是发生在精度不对等的情况,就是前面讨论的扩展了精度和截断了精度的情况。这本身就是数据库使用不正确的问题,并不 能说明float和double不能用在金额上的存储。然而网上并没有人对此深入思考过。不是转载就是重复同一个观点,缺乏思考。
而第三个问题,mysql数据库使用其他数据库引擎来查询,得到的结果会发生精度丢失。这个精度丢失的原因,就可能是不同的数据库引擎对浮点数的精度扩展 和截断处理策略不一致,而且,存储时策略也不一致。所以导致精度会出现各种变化。这种问题也就是催生decimal类型的出现。我们前面看到的 decimal是可以确切存储小数的精度的。因为在存储的时候会将小数以字符串存储,就不会再发生精度的扩展问题。但是decimal依然会发生精度截断 问题。如果decimal指定精度为2位小数,存入的是这样的值:12.123,你觉得结果如何?当然还是会发生四舍五入。结果就是12.12,然而 12.12以字符串形式存入了数据库。此后,12.12始终都是12.12,表现出来的是小数,然而内部是字符串形式存储,所以,小数精度不会再发生变化 了。我们不管以什么精度来获取这个值,都是12.12,而且,不管是一般数据库引擎读取到的也都是12.12,所以decimal才是大家推荐使用的金额 存储类型。
我们应该知道,数据库作为中心,驱动着各种软件的发展,然而在实现上,我们可能用Java方式来访问MySQL,也可能是.Net方式访问mysql,不 同的语言的mysql引擎是有差别的。但是不管怎么样,decimal类型都是可以确定精度的,不会发生四舍五入。所以在各个软件中都表现良好。
所以,不要盲目的说float和double精度可能发生丢失,而是说在存取时因为精度不一致会发生丢失,当然这里的丢失指的是扩展或者截断了,丢失了原 有的精度。decimal是好,但不是说不会发生任何精度丢失。如果问题看得不深入,总会以偏概全。decimal占用的字节多。不过在计算的时候,数据 是准确的。而float和double在计算前一定要对取到的数据的精度做处理,确保和存储的精度一致。而存储的精度也和需要的精度一致,不要长也不要 短。
参考:https://www.jianshu.com/p/c81edc59546c
mysql数据精度丢失问题深入探讨的更多相关文章
- mysql 字符串转数据丢失精度,mysql转换丢失精度,mysql CAST 丢失精度
mysql 字符串转数据丢失精度,mysql转换丢失精度,mysql CAST 丢失精度 =============================== ©Copyright 蕃薯耀 2017年9月1 ...
- springboot 解决Jackson导致Long型数据精度丢失问题
代码中注入一个bean即可: /** * 解决Jackson导致Long型数据精度丢失问题 * * @return */ @Bean("jackson2ObjectMapperBuilder ...
- 找不到mysql.sock,mysql.sock丢失问题解决方法
Can 't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock '(2) "; 是你的mysql ...
- Mysql ibdata 丢失或损坏如何通过frm&ibd 恢复数据
mysql存储在磁盘中,各种天灾人祸都会导致数据丢失.大公司的时候我们常常需要做好数据冷热备,对于小公司来说要做好所有数据备份需要支出大量的成本,很多公司也是不现实的.万一还没有做好备份,数据被误删除 ...
- 关于ORACLE的硬解析和软解析与MySQL的查询缓存query_cache探讨
今天在项目中探讨到Oracle对于SQL语句的解析方法以及MySQL相应的处理方法: --------------------------------------------------------- ...
- 启动mysql错误解决方案,学会查看错误日志:mysql.sock丢失,mysqld_safe启动报错
本人还是个菜鸟,下面是我的经验之谈,能解决一些问题,有不对的地方,敬请斧正. 我的是CentOS6.3+MySQL5.1.57. 重启了一次服务器后,使用> mysql -u root -p登陆 ...
- MySQL更新丢失
MySQL多主结构(比如: MGR Multi Master模式),如果多主都可以写的话,很有可能出现更新丢失的情况. 定义: T1时间,T2时间,T3时间 定义: 事务A, 事务B Node1节 ...
- ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)-mysql.sock丢失解决方案
我们的LAMP是搭建在UBUNTU 12.04 LTS上的. LAMP是通过编译的方式进来安装的. 在一次处理意外挂机时由于未知的原因在重启后发现无法连接数据库了, 在打开网站时出现如下的的提示: E ...
- MySql权限丢失问题解决
参考文章 [mysql] root权限丢失恢复 完全菜鸟教程 今天用root账户登录到mysql后, show databases 命令返回的只有两个表, 然后使用 use database 命令提示 ...
随机推荐
- vue-router 2.0 跳转之router.push()
router.push(location) 除了使用 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现. router.push(location) 想要导航 ...
- struct files_struct
内核利用文件描述符(file descriptor)来访问文件.文件描述符是非负整数.它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表.当程序打开一个现有文件或者创建一个新文件时,内 ...
- grep的用法,小技巧,模板中含有\t时:grep -P "^\t" file
linux中grep和find的用法区别 本文章详细的介绍了关于在linux中的grep和find两个命令的用法介绍,以及后面总结了它们两年用法区别哦. 先我们来介绍一下关于grep用法和一些小注意事 ...
- Linux内核调试方法总结之Kprobes
Kprobes [用途][参考kernel/Documentation/kprobes.txt帮助文档] Kprobes是一个轻量级内核调试工具,同时又是其他一些更高级的内核调试工具(如perf和sy ...
- day03-Python基础
1:函数 定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可 特性: 减少重复代码 使程序变的可扩展 使程序变得易维护 函数定义: def sayh ...
- 职位-CTO:CTO
ylbtech-职位-CTO:CTO 首席技术官是技术资源的行政管理者,英文为Chief Technical Officer或Chief Technology Officer,简称CTO.其职责是制订 ...
- Spring Cloud Stream 使用延迟消息实现定时任务(RabbitMQ)
应用场景 通常在应用开发中我们会碰到定时任务的需求,比如未付款订单,超过一定时间后,系统自动取消订单并释放占有物品. 许多同学的第一反应就是通过spring的schedule定时任务轮询数据库来实现, ...
- 前端005/React生命周期
ES6中React生命周期 一.React生命周期 React生命周期主要包括三个阶段:初始化阶段.运行中阶段和销毁阶段. 在React不同的生命周期里,会依次触发不同的钩子函数. 二.React的生 ...
- python+selenium文本框对象以及按钮对象操作
文本框对象 from selenium import webdriverfrom time import sleep driver = webdriver.Firefox() # 指定和打开浏览器ur ...
- Sentinel整合Dubbo限流实战(分布式限流)
之前我们了解了 Sentinel 集成 SpringBoot实现限流,也探讨了Sentinel的限流基本原理,那么接下去我们来学习一下Sentinel整合Dubbo及 Nacos 实现动态数据源的限流 ...