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

TiDB AUTO_RANDOM 超大主键前端精度丢失排查:JavaScript Number 限制与解决方案

前端长整型主键“失踪”记

——一次 ArrayIndexOutOfBoundsException 的排查全过程


一、事故现场

最近在维护 SMS-OFFICE 后台系统时,运维同事反馈:
点击「短信详情」或「邮箱账号详情」时,偶尔弹窗空白、日志报错:

java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0

抓了一条完整链路,发现请求 URL 是:

/secured/lookSmsMessage.html?contentId=7205759403792883606

而数据库中明明存在这条记录!为什么 SELECT … WHERE content_id = ? 一条都查不到?


二、线索一:前端 JSON 对象异常

打开浏览器 DevTools ➜ Network ➜ Preview,注意到 DataTables 接口返回:

{"contentId": 7205759403792883606,…
}

字段是 裸数字,但和数据库里的大整数完全一致。那问题出在哪里?


三、线索二:JS Number 的“安全整数”

JavaScript 只有一种数值类型 Number,实现为 IEEE-754 双精度浮点。
最大安全整数

Number.MAX_SAFE_INTEGER === 9_007_199_254_740_991

任何大于此值的整数,低位全部失真

主键十进制是否 > 9e15
720 575 940 379 288 3606≈ 7.2 × 10¹⁸
288 230 376 151 801 751≈ 2.88 × 10¹⁷

在控制台验证一下:

JSON.stringify(7205759403792883606)    // "7205759403792884000"

浏览器早在解析 JSON 时,就把它“改写”成了一个近似值 ——
后端再跟这个错误 ID 去查数据库,当然一条也没有。


四、导致的连锁反应

  1. DataTables 渲染
    列内 contentId 被当成 number 存进 rowData,精度丢失。

  2. 按钮拼接 URL

    onclick="lookData(' + rdata.contentId + ')"
    

    结果 rdata.contentId 已经变成错误值。

  3. 后端查询为空list.get(0)IndexOutOfBoundsException.


五、最终定位:纯前端精度问题

  • 数据库:MySQL / TiDB 的 BIGINT,范围 ±9 × 10¹⁸,没问题。

  • 后端:Java long 同样能装下。

  • 真正掉链子 的是浏览器的 Number 精度。


六、修复方案

1. 让主键永远当「字符串」

- onclick="lookData(' + rdata.contentId + ')"
+ onclick="lookData(\'' + rdata.contentId + '\')"
  • 只要在拼接时加一对 引号,JS 就会把它当作字符串传递。

  • 后端 Spring MVC 可以自动把字符串转 Long
    如果你愿意,也可以把参数类型改成 String,然后 Long.valueOf()

2. Mapper / ResultMap 调整

<result column="content_id" property="contentId" jdbcType="VARCHAR"/>

3. 防御式编码

if (list.isEmpty()) {throw new NotFoundException("记录不存在");
}

4. 全链路自检脚本

// Chrome DevTools 快速检测 big int
function hasUnsafeId(json, key='contentId'){return json.some(r => Math.abs(r[key]) > Number.MAX_SAFE_INTEGER);
}

七、最佳实践小结

建议
前端所有主键字段一律用字符串;不要对大整数做数学运算。
后端接口、DTO、Mapper 保持与前端一致的 String/Long;空列表先判空。
数据库如需水平分片可继续用 AUTO_RANDOM;只是传输层别当数值。
日志记录原始请求参数,便于比对是否被截断。

八、一句话总结

当你在前端看到 18 位以上的主键时,第一反应:“加引号!”

避免 JS Number 精度地雷,你的分页、详情、批量操作都会更稳。

http://www.lryc.cn/news/576106.html

相关文章:

  • 玩转Linux CAN/CAN FD—SocketCAN的使用
  • opensuse安装rabbitmq
  • 【编译原理】期末复习知识总结
  • 【大数据】大数据产品基础篇
  • 【开源项目】「安卓原生3D开源渲染引擎」:Sceneform‑EQR
  • ArcGIS Pro利用擦除工具,矢量要素消除另一矢量部分区域
  • 【网络安全】密码学知识普及
  • 高可用与低成本兼得:全面解析 TDengine 时序数据库双活与双副本
  • OkHttp 简单配置
  • pandas---使用教程
  • 解构SAP RISE与Cloud ERP授权新政:从许可模式到迁移策略的深度指南
  • (一)miniconda安装配置
  • Dubbo服务调用超时问题解决方案
  • Hyperledger Fabric 入门笔记(二十)Fabric V2.5 测试网络进阶之Tape性能测试
  • Linux tcp_info:监控TCP连接的秘密武器
  • 【RAG面试题】如何获取准确的语义表示
  • MCP-安全(代码实例)
  • ubuntu安装达梦数据库
  • Java8方法引用:简洁高效的编程利器
  • algorithm ——————》双指针(移动0 复写0 快乐数 装水问题 以及数组中找几个数和为指定的元组)
  • TCP四层模型:网络协议核心解密
  • WPF 3D 开发全攻略:实现3D模型创建、旋转、平移、缩放
  • HTTP协议中Connection: Keep-Alive和Keep-Alive: timeout=60, max=100的作用
  • Linux入门攻坚——49、高可用HA之corosync/pacemaker(2)
  • Linux命令行操作基础
  • 关于css的height:100%
  • JAVA-泛型通配符的上界和下界
  • UUDS—常见NRC及其含义
  • 中国双非高校经费TOP榜数据分析
  • ROS:录制相机、IMU、GNSS等设备数据