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

发布时间:2026/7/31 10:01:52

一次 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()聚合查询ListMapString,ObjectlistempMapper.getJobList();当查询结果以MapString, Object形式返回时MyBatis 并不会把数据库字段智能地映射成你期望的类型而是按照 JDBC 的默认规则转换SQL 类型示例MyBatis / JDBC 默认映射的 Java 类型BIGINT自增主键、COUNT 结果LongINT/INTEGER普通整型字段IntegerDECIMALSUM 金额等BigDecimal注意COUNT(*)、COUNT(1)这类聚合函数的返回类型在 JDBC 规范中是BIGINT因此 MyBatis 会把它映射为Long而不是Integer。2. 为什么强转会失败Long和Integer都是Number的子类彼此之间没有继承关系。Java 的强制类型转换(Integer) obj是针对引用类型的只有在对象的实际运行时类型与目标类型一致或存在继承关系时才能成功。把一个实际是Long的对象强转成IntegerJVM 在运行时就会抛出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再塞进ListInteger。方案一推荐Math.toIntExactjobOption.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明确指定jdbcType与javaType或在 SQL 中使用CAST(COUNT(*) AS SIGNED)等仍然建议接收端用Long因为统计结果本就可能很大。一般来说统计类结果用Long/BigDecimal接收是最稳妥的上面的方案一/二足以应对绝大多数业务。四、经验总结COUNT()、SUM()等聚合函数的结果在 MyBatis 中通常映射为LongBigDecimal而不是Integer。MapString, Object接收查询结果时要清楚每个字段的实际类型不要凭直觉强转。引用类型之间不能随意强转Long/Integer没有继承关系必须用数值转换方法如intValue()、Math.toIntExact()。涉及可能大数值的统计量优先使用Long或BigDecimal承载避免int溢出。一个小小的统计接口背后是对 JDBC 类型映射规则的理解偏差。把Long当Integer用是 MyBatis 初学者最常见的坑之一记住它能省下不少排查时间。

相关新闻