当前位置: 首页 > 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.jsqmd.com/news/1299608/

相关文章:

  • SAP ABAP调用x-www-form-urlencoded接口:从原理到实战
  • 2026 合肥求婚布置避坑指南|策划、场地、花艺挑选完整攻略 - 星际AI
  • 基于规范化标注的中药复方成分分析与代谢产物鉴定策略
  • ESP32 S3驱动SHT40温湿度传感器:从硬件连接到数据读取全解析
  • 九方通逊荣登 2026 晓生榜,获评「跨境电商物流综合实力企业」
  • 联发科设备刷机终极指南:MTKClient 5步快速入门教程
  • 文件夹批量编号:从基础操作到自动化脚本的完整指南
  • JETFAY RX42BR/BL 4合1接收机实战指南:兼容性、对码与飞控集成
  • OpenCSG 最新研究成果入选 ACL 2026:DoGraph 探索大模型数据混合新范式
  • RSA算法深度解析:从数学原理到SSL/TLS、SSH登录实战应用
  • Go语言GOPATH详解:从核心设计到Go Modules演进
  • 日系与欧美彩妆技术对比:配方差异与适用场景全解析
  • 2026年抗静电板指南:原理、四类场景与四大误区 - 万相科技
  • RFID技术赋能武装部应急物资仓储管理
  • 线性一致性
  • 国内规格尺寸齐全的手机LPDDR芯片测试座厂家适配性强
  • Python galois库实战:有限域运算从入门到工程应用
  • 抖音批量下载神器:douyin-downloader完整指南,快速高效获取无水印视频
  • LED驱动电路设计全解析:从恒流原理到Buck电路实战
  • 10分钟搭建商用级智能客服:Coze平台实战指南
  • 抖音直播数据零代码抓取:三分钟开启你的数据洞察之旅
  • 永川区家电维修如何避坑?本地维修干货与正规服务介绍 - 国麟测评
  • 成本因汇率“失真”,ERP如何还原真实利润?
  • 角色动作迁移技术:从骨骼映射到舞蹈动画二次创作实践
  • 阴阳师百鬼夜行AI自动化脚本:三步实现智能砸豆解放双手
  • 本科毕设也查 AIGC 了:第一次写论文的检测扫盲帖
  • Raft如何做到线性一致性
  • QQ空间数据备份完整教程:三步找回全部历史记录的终极指南
  • 村镇微能网建设提速:如何通过数智化运营释放农村能源长期价值?
  • OneMore快捷键系统深度解析:从基础操作到高效工作流