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

一次 MyBatis 统计查询引发的 ClassCastException:Long 不能强转为 Integer

关键词:MyBatis、ClassCastException、COUNT 聚合、类型映射、Spring Boot

一、问题的出现

在一个 Spring Boot + MyBatis 的报表统计接口中,调用ReportServiceIml.getEmpJobData()时,控制台抛出了如下异常:

java.lang.ClassCastException: class java.lang.Long cannot be cast to class java.lang.Integer at com.mlamp.service.impl.ReportServiceIml.lambda$getEmpJobData$1(ReportServiceIml.java:24) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)

报错位置指向第 24 行:

jobOption.setDataList(list.stream().map(m->(Integer)m.get("count")).toList());

异常堆栈很清晰地告诉我们:Long类型的对象无法被强转为Integer

二、根因分析

1. MyBatis 对聚合函数结果类型的默认映射

我们的数据来自一条COUNT()聚合查询:

List<Map<String,Object>>list=empMapper.getJobList();

当查询结果以Map<String, Object>形式返回时,MyBatis 并不会把数据库字段"智能"地映射成你期望的类型,而是按照 JDBC 的默认规则转换:

SQL 类型示例MyBatis / JDBC 默认映射的 Java 类型
BIGINT自增主键、COUNT 结果Long
INT/INTEGER普通整型字段Integer
DECIMALSUM 金额等BigDecimal

注意:COUNT(*)COUNT(1)这类聚合函数的返回类型在 JDBC 规范中是BIGINT,因此 MyBatis 会把它映射为Long,而不是Integer

2. 为什么强转会失败?

LongInteger都是Number的子类,彼此之间没有继承关系。Java 的强制类型转换((Integer) obj)是针对引用类型的,只有在对象的实际运行时类型与目标类型一致(或存在继承关系)时才能成功。把一个实际是Long的对象强转成Integer,JVM 在运行时就会抛出ClassCastException

这与"自动拆箱 + 数值转换"是两回事。(int) longValue这种基本类型转换是合法的,但(Integer) (Long 对象)这种引用类型转换是不合法的。

3. 出错代码

// 字段实际上是一个 Long 对象jobOption.setDataList(list.stream().map(m->(Integer)m.get("count")).toList());

m.get("count")返回的是Long,再(Integer)强转,于是炸了。

三、解决方案

目标:把Long安全、明确地转换为int,再塞进List<Integer>

方案一(推荐):Math.toIntExact

jobOption.setDataList(list.stream().map(m->Math.toIntExact((Long)m.get("count"))).toList());

Math.toIntExact(long)会把long转为int,并在数值超出int取值范围(-2^31 ~ 2^31-1)时主动抛出ArithmeticException。对统计数据量这种场景,这是一个安全的"早失败"保护。

方案二:直接调用intValue()

jobOption.setDataList(list.stream().map(m->((Long)m.get("count")).intValue()).toList());

简单直接,但数值溢出时不会报错(直接截断高位),适合你能确定数据量不会爆int范围的场景。

方案三(治本):从 SQL/结果类型上规避

如果希望从根源上得到Integer,可以在 Mapper 中:

  • 使用@MapKey或定义专门的 DTO/实体类,配合<result>明确指定jdbcTypejavaType
  • 或在 SQL 中使用CAST(COUNT(*) AS SIGNED)等(仍然建议接收端用Long,因为统计结果本就可能很大)。

一般来说,统计类结果用Long/BigDecimal接收是最稳妥的,上面的方案一/二足以应对绝大多数业务。

四、经验总结

  1. COUNT()SUM()等聚合函数的结果,在 MyBatis 中通常映射为LongBigDecimal),而不是Integer
  2. Map<String, Object>接收查询结果时,要清楚每个字段的实际类型,不要凭直觉强转。
  3. 引用类型之间不能随意强转Long/Integer没有继承关系,必须用数值转换方法(如intValue()Math.toIntExact())。
  4. 涉及可能大数值的统计量,优先使用LongBigDecimal承载,避免int溢出。

一个小小的统计接口,背后是对 JDBC 类型映射规则的理解偏差。把LongInteger用,是 MyBatis 初学者最常见的坑之一,记住它,能省下不少排查时间。

http://www.cnnetsun.cn/news/3764055.html

相关文章:

  • 如何自定义TranslucentTB让Windows任务栏变透明:释放桌面美学的终极方案
  • 3C电子行业SEO优化策略与私域流量构建
  • Unity 3D冒险游戏开发实战:从沉浸感设计到性能优化全流程
  • 万科净水器自有制造基地品牌家用净水设备源头工厂品牌全国联保
  • C++ std::stack 核心原理与实战:从 LIFO 思想到括号匹配与表达式求值
  • 深入理解STM32系统架构与时钟树:从原理到实践
  • DLSS Swapper完全指南:3步掌握游戏画质优化终极技巧
  • 不要问模型是 Transformer 还是 Diffusion:一套五层技术栈检查法(系统角色 / 表示空间 / 网络骨架 / 训练范式 / 推理算法)
  • 【单片机毕设案例分享】基于嵌入式传感的婴儿尿床哭声监测系统设计 基于 STM32 单片机的多模块婴儿看护设备开发(012201)
  • 2026年夜宵烧烤习惯与大便黏腻关系解析及调理建议
  • 长鑫科技“估值登顶”背后:是国内垄断,还是全球存储暴风圈?
  • 3分钟上手本地视频字幕提取:免费高效的多语言硬字幕提取终极指南
  • 联发科设备刷机终极指南:MTKClient 5步快速入门教程
  • 深度优先搜索与递归回溯:从全排列问题解析算法核心
  • QRRanker:基于LLM推理能力的RAG系统排序优化框架
  • 从零搭建千万级营收预测AI系统:TensorFlow+XGBoost双模融合架构(含2024Q2实测ROI对比表)
  • 识货商品数据爬取实战:Puppeteer反反爬方案
  • 如何从游戏修改器的限制中解放出来?Wand-Enhancer让专业功能触手可及
  • STM32CubeMX图形化配置工具:从环境搭建到多任务开发的实战指南
  • Doris副本修复实战:从状态机到手动修复的完整指南
  • 2026中国企业ERP选型指南:吉客云凭什么能够脱颖而出?
  • C++引用与指针深度对比:从底层实现到最佳实践
  • Zepp Life智能步数管家:5分钟搭建你的24小时健康数据自动化方案
  • LangGraph框架解析:AI智能体开发的核心优势与实践指南
  • 射频衰减器设计:从T型/PI型理论计算到ADS高频仿真全流程
  • 5分钟快速备份QQ空间历史说说:GetQzonehistory完整使用教程
  • 短视频代运营合同怎么写才不吃亏?
  • Spring Cloud Alibaba版本选择与兼容性实战指南
  • 电动船智能航行系统
  • ChatTTS:新一代中文语音合成技术解析与实战