当前位置: 首页 > backend >正文

【Mysql】字段隐式转换对where条件和join关联条件的影响

【Mysql】字段隐式转换对where条件和join关联条件的影响

  • 【一】问题描述
  • 【二】问题分析
    • 【1】类型不匹配触发隐式转换(字符转数值)
    • 【2】大整数转换的精度丢失问题
    • 【3】具体场景解释
  • 【三】字段类型转换的原理
    • 【1】转换方向:字符串→数值(而非数值→字符串)
    • 【2】转换规则与风险
    • 【3】转换过程的细节:字符串→数值的溢出处理
    • 【4】示例:
    • 【5】典型现象:相近数值的错误匹配
  • 【四】解决方法
    • 【1】方案1:传参时将Long转为String
    • 【2】方案2:统一表字段类型

【一】问题描述

数据库中用户表主键id是bigint类型,由雪花算法生成的id。另一个中间表的字段userId存的是varchar类型。使用MybatisPlus执行sql,传参是Long类型,出现以下两种情况:
(1)使用Long类型的参数userId=728666272023183375,从中间表里删除记录,会把userId=728666272023183374的记录也删除了
(2)使用用户表和中间表leftjoin的使用,用户表的id是bigint,中间表的userId是varchar,728666272023183375的用户会把728666272023183374的关联信息也查出来

根据上述情况分析,无论是where查询还是关联表join,都存在等号两边的字段类型不一致,出现字段类型隐式转换导致的精度丢失,导致查询错误

【二】问题分析

上述问题的核心原因是数据库隐式类型转换导致的数值匹配异常,具体如下:

【1】类型不匹配触发隐式转换(字符转数值)

用户表的id是bigint类型(数值型),中间表的userId是varchar类型(字符串型)。当用Long类型(对应数据库bigint)的参数与varchar字段比较时,数据库会触发隐式类型转换:将varchar类型的userId转换为数值型(而非将bigint转换为字符串)后再进行比较。

【2】大整数转换的精度丢失问题

MyBatis-Plus 雪花算法默认生成的 ID 是 19 位长整数,雪花算法生成的 ID 是 18-19 位的大整数(如728666272023183375)

MySQL 中用于存储大整数的主要类型是BIGINT,其精度存在硬性限制:
(1)BIGINT是 64 位有符号整数,取值范围为 -9223372036854775808 ~ 9223372036854775807(约 ±9e18)。
(2)这个范围对应的最大有效数字是18 位(9223372036854775807 是 19 位数字,但前 18 位是有效范围)。

数据库对数值类型的精度处理存在限制:
部分数据库(如 MySQL)对bigint的最大支持是 64 位有符号整数(范围约 ±9e18),但当varchar字段存储的字符串转换为数值时,若数值接近最大范围,可能因精度不足导致近似匹配(如728666272023183375和728666272023183374在转换后被误判为相等)。

字符串转数值时,若存在格式问题(如末尾有不可见字符),也可能导致转换后的数值与预期不符,进而匹配错误。

【3】具体场景解释

删除场景:执行DELETE FROM 中间表 WHERE userId = ?时,参数是Long类型(数值),数据库将userId(varchar)转为数值后比较。因精度丢失,728666272023183375和728666272023183374的转换结果被误判为相等,导致误删。
关联查询场景:LEFT JOIN的ON条件中,user.id(bigint)与中间表.userId(varchar)比较时,同样触发隐式转换,导致相近 ID 的关联信息被错误匹配。

【三】字段类型转换的原理

数据库处理不同类型字段的比较时,遵循隐式类型转换规则,核心逻辑如下:

【1】转换方向:字符串→数值(而非数值→字符串)

当数值类型(bigint/int)与字符串类型(varchar)比较时,数据库默认将字符串转换为数值后再比较,而非将数值转为字符串。原因是数值比较的优先级高于字符串比较(数据库认为数值语义更精确)。

【2】转换规则与风险

若字符串是纯数字(如"123"),转换为数值后可正常比较。
若字符串包含非数字字符(如"123a"),转换后可能为0或NULL(不同数据库行为不同)。
若字符串是超长数字(如 19 位以上),转换时可能因超出数据库数值类型的精度范围,导致截断、四舍五入或溢出,进而出现匹配错误(即本文问题的根源)。

【3】转换过程的细节:字符串→数值的溢出处理

MySQL 将字符串转换为数值时,遵循以下规则(以 19 位纯数字字符串为例):
(1)尝试将字符串解析为BIGINT类型(默认优先匹配最大的整数类型)。
(2)若字符串数值≤9223372036854775807(BIGINT最大值):可精确转换(18 位及以内的数值通常没问题)。
(3)若字符串数值>9223372036854775807:
MySQL 无法用BIGINT精确表示,会自动转为DOUBLE(双精度浮点数)处理。
但DOUBLE的精度有限(有效数字为 15-17 位),对于 19 位数值,超出 17 位的部分会被四舍五入或截断,导致精度丢失。

【4】示例:

字符型字段存储:“9223372036854775808”(19 位,超过BIGINT最大值)。
转换为DOUBLE后,可能被近似为9223372036854776000(后几位因精度不足被截断)。
此时若查询条件的数值参数是9223372036854775808,转换后与字段转换结果可能匹配,也可能因近似值冲突导致错误匹配(如与9223372036854775809的转换结果相同)。

【5】典型现象:相近数值的错误匹配

由于 19 位数值转换后精度丢失,会导致原本不同的数值在转换后被判定为相等,表现为:
用WHERE user_id = 728666272023183375(数值参数)查询时,可能同时匹配"728666272023183375"和"728666272023183374"(字符型字段值)。
原因是这两个 19 位数值转换为DOUBLE后,因精度限制被近似为同一个值(后几位差异被忽略)。

【四】解决方法

核心原则:避免隐式类型转换,确保比较双方类型一致。具体实现如下:

【1】方案1:传参时将Long转为String

在 Java 代码中,将Long类型的userId转换为String后再传入 SQL,确保参数与varchar字段类型一致,避免触发隐式转换。

// 错误:传Long类型
Long userId = 728666272023183375L;
queryWrapper.eq("user_id", userId); // 触发隐式转换// 正确:转为String后传参
String userIdStr = String.valueOf(userId);
queryWrapper.eq("user_id", userIdStr); // 字符串直接比较,无转换

【2】方案2:统一表字段类型

最彻底的方式是修改中间表的userId字段类型为bigint,与用户表的id类型保持一致,从根源上消除类型转换问题。

http://www.xdnf.cn/news/16776.html

相关文章:

  • Oracle EBS 缺少adcfgclone.pl文件
  • 链接脚本中. = ALIGN(4);的作用?
  • 北斗变形监测在地质灾害监测中的应用
  • 浅谈低代码平台涉及的一些技术选型
  • AI Agent 视角:可执行程序的二进制格式,是一场「结构化语言」与「智能解析」的双向奔赴
  • UE5多人MOBA+GAS 番外篇:同时造成多种类型伤害,以各种属性值的百分比来应用伤害(版本二)
  • 流式编程的中间操作
  • linux编译基础知识-编译时路径和运行时路径
  • 在Idea中,配置maven
  • Galaxea机器人由星海图人工智能科技有限公司研发的高性能仿人形机器人
  • 【C语言】预处理详解
  • 高防服务器租用:保障数据安全
  • Nginx跨域问题与 MIME 类型错误深度排错指南:解决 MIME type of “application/octet-stream“ 报错
  • PyTorch分布式训练深度指南
  • 26数据结构-顺序表
  • 【数据结构与算法】21.合并两个有序链表(LeetCode)
  • 如何将消息转移到新 iPhone
  • 深入剖析Spring IOC容器——原理、源码与实践全解析
  • Linux---编辑器vim
  • 嵌入式学习笔记-MCU阶段-DAY10ESP8266模块
  • 初识微服务
  • 飞算 JavaAI 中 SQL 另存为脚本功能详解
  • ZKmall开源商城微服务架构电商平台:服务注册与配置中心设计
  • 充电桩与照明“联动”创新:智慧灯杆破解新能源基建难题
  • 微服务消息队列之RabbitMQ,深入了解
  • 【unity小技巧】封装unity适合2D3D进行鼠标射线检测,获取鼠标位置信息检测工具类
  • Java设计模式之行为型模式(解释器模式)实现方式详解
  • Elasticsearch 集群管理核心 API 指南:健康、状态、分片诊断与运维实战
  • 调试 Rust 生成的 WebAssembly
  • 工业级蓝光三维扫描仪:汽车零部件高精度检测的利器