当前位置: 首页 > 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.lqws.cn/news/550459.html

相关文章:

  • 内测开启!看海量化回测系统V2.0版本更新,基于miniQMT的回测系统问世!
  • Threejs开发指南(第七篇 利用AI进行threejs开发)
  • 封装nuxt3的SSR请求和CSR请求方法
  • 1 Studying《Is Parallel Programming Hard》6-9
  • 双指针技巧深度解析
  • C#系统学习第二章——第一个C#程序
  • P27:RNN实现阿尔茨海默病诊断
  • 华为云Flexus+DeepSeek征文|基于Dify+ModelArts开发AI智能会议助手
  • 本地部署 WordPress 博客完整指南(基于 XAMPP)
  • nt!MiFlushSectionInternal函数分析从nt!IoSynchronousPageWrite函数到Ntfs!NtfsFsdWrite函数
  • 三阶落地:腾讯云Serverless+Spring Cloud的微服务实战架构
  • React中的ErrorBoundary
  • 【经验】新版Chrome中Proxy SwitchyOmega2已实效,改为ZeroOmega
  • 车载诊断架构 --- 诊断与ECU平台工作说明书
  • SQL Server for Linux 如何实现高可用架构
  • 【策划所需编程知识】
  • 中国双非高校经费TOP榜数据分析
  • 【记录】Ubuntu|Ubuntu服务器挂载新的硬盘的流程(开机自动挂载)
  • SQL学习笔记4
  • MFC获取本机所有IP、局域网所有IP、本机和局域网可连接IP
  • 一起endpoint迷路的问题排查总结
  • 浅谈Apache HttpClient的相关配置和使用
  • git add 报错UnicodeDecodeError: ‘gbk‘ codec can‘t decode byte 0xaf in position 42
  • SOCKS 协议版本 5 (RFC 1928)
  • 【stm32】HAL库开发——CubeMX配置串口通讯(中断方式)
  • VUE使用过程中的碰到问题记录
  • 自动对焦技术助力TGV检测 半导体检测精度大突破
  • 工作台-02.代码开发
  • Linux信号机制:从入门到精通
  • [Python]-基础篇1- 从零开始的Python入门指南