【已解决】MySQL:执行sql查询出错误数据(MySQL隐藏机制-类型转换导致)

目录

问题现象:

问题分析:

        结论:

解决方法:

拓展:


问题现象:

        今天在项目开发中发现了一个非常奇怪的bug:

        如图,我在数据库中以“dept_id = 1712651046956421123”为条件,执行了sql查询,但是查询出来的结果显示:dept_id 是 1712651046956421122

        当时是在查看项目的服务日志,排查问题的时候才看出来这个奇怪的现象,还以为是bug,查了一下资料终于知道了具体原因,确实是个大坑,特此记录。


问题分析:

        一开始还以为是mysql8+的bug,但是想了想事情可能没有这么简单,于是就开始我的实验测试:

        首先、我用navicat工具直接去这个表里面进行可视化筛选,发现:以“dept_id = 1712651046956421123”为条件查询不出来数据,以以“dept_id = 1712651046956421122”则可以查询出数据:

        

        

        由此可见navicat工具的筛选功能是没有问题的,于是我分别尝试用这两个dept_id值(即1712651046956421123和1712651046956421122)去执行sql来查询,发现:还是可以查询出相同的结果:

        

        
        这就让我很纳闷了,一时间毫无头绪,只好上网查一下资料,终于在MySQL官网的一篇讲解中,我知道了具体原因,重点在于我红框标注的这个地方:

        

        感兴趣的小伙伴可以看看,这里我贴上链接:

        MySQL :: MySQL 5.7 Reference Manual :: 12.3 Type Conversion in Expression Evaluation   

        根据讲解中提到的例子,我直接去数据库里执行sql,这里就不一一贴出结果来了,直接贴sql代码和结果,感兴趣的小伙伴可以自己去验证一下:

select 1712651046956421123 = 1712651046956421123;-- 结果:1
select 1712651046956421122 = 1712651046956421122;-- 结果:1
select 1712651046956421123 = 1712651046956421122;-- 结果:0select '1712651046956421123' = '1712651046956421123';-- 结果:1
select '1712651046956421123' = 1712651046956421123;-- 结果:1
select '1712651046956421123' = 1712651046956421122;-- 结果:1select '1712651046956421122' = '1712651046956421122';-- 结果:1
select '1712651046956421122' = 1712651046956421122;-- 结果:1
select '1712651046956421122' = 1712651046956421123;-- 结果:1

        相信有部分小伙伴已经看出原因来了,下面我再贴个图,估计大家就完全懂了:

        

        建表sql如下:

CREATE TABLE `xxxxxxxxxxxxxx_dept` (`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '名称',`dept_id` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '部门id',PRIMARY KEY (`dept_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1712757077034344450 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='部门信息表';

        其实就是因为这个dept_id的字段类型设置成了varchar类型,也就是字符串类型,但是我执行sql 时传入的是整型数值,而不是字符串类型的数值,这就会触发mysql的隐藏机制,数据类型转换,然后就可能会触发意想不到的问题,从文章的解释文字可以知道:

        翻译后的意思大概就是:

        当发生从字符串到浮点从整数到浮点的转换时,它们不一定以相同的方式发生。整数可以由CPU转换为浮点,而字符串则在涉及浮点乘法的操作中逐位转换。此外,结果可能受到计算机体系结构或编译器版本或优化级别等因素的影响。避免此类问题的一种方法是使用CAST(),这样值就不会隐式转换为浮点数。

        由于可见,其实文章开头提到的问题,发生的具体原因就是:

        当对字符串类型的字段赋值为整数类型时,会发生类型转换,整数转为浮点数,而浮点数是带有精度的,当浮点数超过一定的精度值时,在精度值前的数据如果是一致的,则会被认为是相等的值。

        通过肉眼观察1712651046956421123和1712651046956421122,就可以发现,这两数值其实就只是最后一位数字不同,前面的数据是完全相同的,因此符合我的推论。

        接下来我们在继续测试并验证一下我的推论:

select '1234567890' = 1234567891;-- 结果:0
select '123456789012345' = 123456789012341;-- 结果:0
select '123456789012345678' = 123456789012345671;-- 结果:0
select '1234567890123456789' = 1234567890123456781;-- 结果:1
select '12345678901234567890' = 12345678901234567891;-- 结果:1
select '1234567890123456789012345678901234567890' = 1234567890123456789012345678901234567891111;-- 结果:1
select '12345678901234567899999' = 12345678901234567811111;-- 结果:1
select '1234567890123456789012345678901234567890' = 1234567890123456789012345678901234567891111111111111111;-- 结果:0
select 1234567890123456789 = 1234567890123456781;-- 结果:1

        亲测发现,这个精度的临界值就是18位数,也就是说如果 = 左右两边的数值长度一样,且数值的长度>18位数时,如果数据类型不同触发了类型转换,则会直接判断 = 左右两边的前面18位数的数值;如果完全一致,则不管后面的数据有多大差异都会认为是相等的。

        结论:

       出现开头提到的问题现象的具体原因如下:

        1、当where条件中的字段和赋值数据的类型不同(主要指字符串、整数、浮点数,其他的数据类型感兴趣的小伙伴可以自己去测试一下)时,会触发类型转换机制字符串->整数->浮点数】。

        2、触发类型转换机制时,如果满足以下条件会被判断为 = 左右两边的数据相等:

        2.1、两边的数据长度相同;

        2.2、两边的数据长度都>18位数;

        2.3、两边的数据前18位数的数值完全一致;


解决方法:

        为了避免这个因为触发了MySQL的类型转换的隐藏机制,而导致类似于文章开头举例的这种查询出错误结果集的问题,这里提供一些我能想到的解决方法,还原补充:

        1、就如文章中提到的MySQL官网,其实已经给了一种解决方法,那就是使用CAST函数,将数据做一下类型转换,这样就不会触发类型转换的机制,自然也就能避免问题发生。

select '1234567890123456789' = 1234567890123456781;-- 结果:1
select CAST('1234567890123456789' as UNSIGNED) = 1234567890123456781;-- 结果:0

        不过这里并不建议采用这种方法,因为它具有sql代码侵入性,代码修改的维护成本比较高,而且治标不治本。

        2、修改表字段,在定义表字段类型的时候,应该想清楚这个字段要存储什么类型的数据,然后在代码中要保证类型是对应的(如varchar类型字段对应JAVA中的String类型),这样执行sql的时候就能保证数据类型一致,防止触发类型转换的机制,自然也就能避免问题发生。

        强烈建议采用这种方法,因为只要大家都遵守规范自然就能避免问题。


拓展:

        当然,也许有人会问为啥MySQL不直接去掉这个类型转换的隐藏机制呢?

        要知道,事情都是由两面性的,类型转换的隐藏机制其实也有很多好处,不去掉自然是因为利大于弊;这里就不仔细举例了,因为不在本文的谈论范围,后续可能会出一篇新的文章详细说明一下。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/157127.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WEEX编译|加密市场三季度回顾及未来展望

作者:Greg Cipolaro,NYDIG 全球研究主管 编译:WEEX 唯客交易所 本文要点: ● 在充满挑战的第三季度,比特币价格下跌 11.1%,因为众多资产类别都在努力应对利率上升的影响和对经济衰退的担忧。 ● 比特币…

CentOS 7 基于C 连接ZooKeeper 客户端

前提条件:CentOS 7 编译ZooKeeper 客户端,请参考:CentOS 7 编译ZooKeeper 客户端 1、Docker 安装ZooKeeper # docker 获取zookeeper 最新版本 docker pull zookeeper# docker 容器包含镜像查看 docker iamges# 准备zookeeper 镜像文件挂载对…

什么是指标体系,怎么搭建一套完整的指标体系?(附PDF素材)

什么是指标体系,怎么搭建一套完整的指标体系?数字化转型过程中,这个问题一直困扰着数据分析师。主要体现在: 各部门根据业务需求,都有一部分量化指标,但不够全面,对企业整体数据分析应用能力提…

3D机器视觉:解锁未来的立体视野

原创 | 文 BFT机器人 机器视觉领域一直在不断演进,从最初的二维图像处理,逐渐扩展到了更复杂的三维领域,形成了3D机器视觉。3D机器视觉技术的涌现为计算机系统带来了全新的感知和理解能力,这一领域的发展正日益受到广泛关注。本文…

掌动智能浅析Web自动化测试的重要性

在现代Web开发中,确保Web应用程序的质量和稳定性至关重要。Web自动化测试工具成为了开发团队的关键资源,帮助他们自动化测试流程、减少手动劳动,提高测试覆盖率和效率。本文将介绍Web自动化测试的重要性是什么! Web自动化测试的重要性&#x…

PanoFlow:学习360°用于周围时间理解的光流

1.摘要: 光流估计是自动驾驶和机器人系统中的一项基本任务,它能够在时间上解释交通场景。自动驾驶汽车显然受益于360提供的超宽视野(FoV)◦ 全景传感器。 然而,由于全景相机独特的成像过程,为针孔图像设计…

【二甲医院his系统源码】医疗卫生信息化大数据平台源码

基于云计算技术的SaaS服务的医院信息系统源码 云HIS系统有效实现医疗数据共享与交换,解决数据重复采集及信息孤岛等问题。重构管理服务流程,重建统一的信息架构体系,重造病人服务环境,向不同类型的医疗机构提供SaaS化HIS服务解决…

业务安全五重价值:防攻击、保稳定、助增收、促合规、提升满意度

目录 防范各类威胁攻击 保障业务的连续性和稳定性 保障业务的合规性 提升企业营收和发展 提升企业满意度和品牌知名度 2023年暑假被“票贩子”和“黄牛”攻陷。他们利用各种手段抢先预约名额,然后加价出售给游客,导致了门票供不应求的局面&#xff…

[42000][923] ORA-00923: 未找到要求的 FROM 关键字

在oracle数据库写分页查询,使用 rownum时候出错, 代码: SELECT *FROM (SELECT *, ROWNUM AS rnumFROM test t ) WHERE rnum BETWEEN 1 AND 5; 报错: [42000][923] ORA-00923: 未找到要求的 FROM 关键字 Position: 31 问题原因…

1014蓝桥算法双周赛,学习算法技巧,助力蓝桥杯

家人们,我来免费给大家送福利了!!! 【1014蓝桥算法双周赛 】 背景 蓝桥杯全国软件和信息技术专业人才大赛是由工业和信息化部人才交流中心举办的全国性IT学科赛事。参赛高校超过1200余所,累计参赛人数超过40万人。该…

如何理解BFC、开启BFC、BFC解决哪些问题

1.BFC 概念 BFC 英文名为 Block Formatting Context (块级格式化上下文) 具体可查看 MDN 2.BFC的作用 元素开启BFC后,子元素不会发生margin塌陷问题元素开启BFC后,子元素浮动,元素不发生高度塌陷元素开启BFC后,该元素不被其他元…

java案例RSA分段加密解密,签名验签,公钥加密私钥解密,私钥加密公钥解密,解密乱码怎么解决

一. 原理 非对称加密算法是一种密钥的保密方法。 非对称加密算法需要两个密钥:公开密钥(publickey:简称公钥)和私有密钥(privatekey:简称私钥)。公钥与私钥是一对,如果用公钥对数据进行加密,只…

纯 CSS 实现瀑布流布局的方法

纯 CSS 实现瀑布流布局的方法 这种方式兼容性不是很好,全部支持需要些时间,但是目前是可以使用 css 写出来的 display: grid; grid-template-columns: repeat(4, 1fr); grid-gap: 10px; grid-template-rows: masonry;全部的 css .container {display:…

凉鞋的 Godot 笔记 108. 第二个通识:增删改查

在这一篇,我们来学习此教程的第二个通识,即:增删改查。 增删改查我们不只是一次接触到了。 在最先接触的场景窗口中,我们是对 Node 进行增删改查。 在文件系统窗口中,我们是对文件&文件夹进行增删改查&#xff1…

【单片机】18-红外线遥控

一、红外遥控背景知识 1.人机界面 (1)当面操作:按键,旋转/触摸按键,触摸屏 (2)遥控操作:红外遥控,433M/2.4G无线通信【穿墙能力强】,蓝牙-WIFI-Zigbee-LoRa等…

jupyter 切换虚拟环境

当前只有两个环kernel 我已经创建了很多虚拟环境,如何在notebook中使用这些虚拟环境呢?请看下面 比如说我要添加nlp 这个虚拟环境到notebook中 1. 切换到nlp环境 2. 安装如下模块 pip install ipykernel 3. 执行如下命令 python -m ipykernel install …

【IDEA项目个别类爆红,但是项目可以正常运行】

打开项目时发现idea个别类爆红,但是项目可以正常运行 问题原因:Idea本身的问题,可能是其缓存问题,导致爆红 解决方案:重置Idea 很多时候排查不出代码问题,就尝试一下此操作。 选择目录:File–>Invalida…

今日头条文章采集ChatGPT3.5/4.0驱动浏览器改写文章软件说明文档

大家好了,我是淘小白~ 今天给大家介绍的软件是一个款驱动浏览器改写文章的软件,下面给大家做一下介绍说明: 一、软件语言 Python编写的,使用的库是selenium库 二、具体逻辑 1、整理头条文章网址,需要自己整理&…

【广州华锐互动】钢厂铸锻部VR沉浸式实训系统

随着科技的不断进步,虚拟现实(VR)技术已成为当今最具潜力的技术之一。在钢铁行业中,VR虚拟仿真实训已经被广泛应用于培训和教育领域,特别是钢铁厂铸锻部,通过VR技术,可以大大提高培训效率,降低培训成本&…

多域名SSL数字证书是什么呢

多域名SSL数字证书是众多SSL数字证书中最灵活的一款SSL证书产品。一般一张SSL证书只能保护一个域名,即使能保护多个域名站点,证书保护的域名类型也有限制(通配符SSL数字证书)。多域名SSL数字证书既能用一张SSL证书保护多个域名网站,又不限制域…