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

news2024/11/21 1:32:11

目录

问题现象:

问题分析:

        结论:

解决方法:

拓展:


问题现象:

        今天在项目开发中发现了一个非常奇怪的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;-- 结果:0

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

select '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.coloradmin.cn/o/1088369.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【强烈推荐】免费的PDF工具,包括PDF拆分/分割、转WORD等功能的免费在线软件工具,救了大命,找了半天什么pdf365、福xipdf、还有哔果pdf全是打着免费名义收费,烦死了

PDF拆分 - 图文工具箱 - imgtool.net,嘎嘎好用,主要是免费 除此之外,还有其他的功能,需要的可以去看看

[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 问题原因…

低代码平台为企业应用开发提速

一、背景 应用开发周期长一直是IT部门和业务部门面临的问题。 IT部门总是被新的应用需求弄得不堪重负。他们不可能完成业务部门想要完成的每一个项目。同时,业务部门的用户厌倦了等待,并开始完全绕过IT部门。 今天,我们来探索一下“低代码开发…

浅谈压力测试的作用是什么

随着现代应用程序变得越来越复杂,用户的期望也在不断提高,对性能和可靠性的要求变得更加苛刻。在应用程序开发和维护的过程中,压力测试是一项至关重要的活动,它可以帮助发现潜在的问题、评估系统的性能极限,以及确保在…

js内存与数据

1.内存空间的重要性 想要对js理解更深刻,就需要对内存空间有个清晰的认知。 比如基本和引用数据类型存储方式和引用传递到底是怎么回事? 栈内存与堆内存的区别? 2.计算机存储空间 内存:容量小 访问速度快 程序运行时&#xff…

微型导轨可用在哪些设备上?

微型导轨是一种高精度、小体积的导轨系统,被广泛应用于各种需要高精度导向的场合。以下是一些常见的微型导轨应用场景: 1、半导体设备:在半导体制造过程中,设备需要精确、高速和稳定的运动。微型导轨具有高精度和高刚性&#xff0…

【管理运筹学】第 10 章 | 排队论(1,排队论的基本概念)

文章目录 引言一、基本概念1.1 排队过程1.2 排队系统的组成和特征1.3 排队模型的分类1.4 系统指标1.5 系统状态 引言 开一点排队论的内容吧,方便做题。 排队论(Queuing Theory)也称随机服务系统理论,是为解决一系列排队问题&…

工业互联网系列1 - 智能制造中有哪些数据在传输

工业互联网以网络为基础,需要传输的数据种类多种多样,这些数据对于实时监控、生产优化、设备维护和决策支持等方面都至关重要。 以下是一些常见智能制造业中需要传输的数据类型: 传感器数据:制造设备上安装的传感器(如…

高效视频剪辑:批量合并视频与背景音乐结合的技巧解析

在数字媒体时代,视频剪辑已经成为了一种重要的技能。其中,批量合并视频与添加背景音乐是视频剪辑过程中不可忽视的环节。本文将为您提供高效地合并视频和背景音乐的技巧解析,帮助您更快速地完成视频剪辑,创作出更加生动有趣的视频…

加固数据安全:Java助力保护Excel文件,让数据无懈可击

摘要:本文由葡萄城技术团队于CSDN原创并首发。转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具、解决方案和服务,赋能开发者。 前言 Excel文件保护是常用的一种功能,文件保护主要有三种: 添…

OLED透明拼接屏:福州鼓山风景区:徜徉于城市壮丽之

福州是中国福建省的省会城市,历史悠久,文化底蕴深厚。 该城市曾是唐宋时期的重要港口城市,也是丝绸之路海上丝绸之路的起点之一。 福州以其独特的地理位置和丰富的历史遗产而闻名于世。 福州拥有众多的历史景点,其中最著名的是…

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

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

给电瓶车“消消火”——TSINGSEE青犀智能电瓶车棚监控方案

近年来,电瓶车电梯起火、室内起火、楼道起火的新闻层出不穷,很多人为了图方便就将电瓶车推到家中充电,这种十分危险的行为,严重影响了社区的公共安全和个人生命财产,为什么惨痛新闻不断播出,这种行为还是屡…

java 并发AQS 理解

最近复习并发中AQS相关知识,这边看到一个比较好的文章,转载记录下 转载自:Java AQS 核心数据结构-CLH 锁 在并发编程中,锁是一种常用的保证线程安全的方法。Java 中常用的锁主要有两类,一种是 Synchronized 修饰的锁…

html页面提交数据后,数据库有新增但为空值

经过仔细查找错误的原因,发现问题就出在我的html文件 红色箭头指示的语句我没加进去

vscode中注释多行bash脚本

选择你要注释的行,右击所选的行,从命令调色板中选择添加行注释。 选择后,所选的行将被注释为#,如下图所示。 选择你想取消注释的行,在所选行上点击右键,从命令调色板中选择删除区块注释,就可以从…

【力扣每日一题】2023.10.13 避免洪水泛滥

目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 给我们一个一维数组,元素为0表示对应日期不下雨,非0则表示对应日期对应号的湖泊下雨,下雨之后会导致该…

01-10 周二 PyCharm远程Linux服务器配置进行端点调试

01-10 周二 PyCharm远程Linux服务器配置 时间版本修改人描述2023年1月10日14:04:15V0.1宋全恒新建文档2023年2月6日11:03:45V0.2宋全恒添加快捷指令别名的实现方便虚拟环境的切换 简介 使用 PyCharm,您可以使用位于另一台计算机(服务器)上的解释器调试应用程序。 …

HotSpot的算法实现

1.根节点的枚举 我们通过可达性分析算法从GC Roots中找到全局性的引用(例如常量或者类静态属性)或者是执行上下文(例如栈帧中的本地变量)中,尽管我们的目标非常明确,但是随着java的不断扩大,光一…

JTS: 12 Descriptions 图形覆盖

这里写目录标题 版本代码Intersection 交集Union 并集Difference 差集SymDifference 补集 版本 org.locationtech.jts:jts-core:1.19.0 链接: github 代码 /*** 图形覆盖操作* author LiHan* 2023年10月12日 19:34:09*/ public class GeometryDescriptions {private final Ge…