You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring MVC+Hibernate按Driver分组查询异常排查与实现咨询

排查Spring MVC+Hibernate Group By数据显示异常问题

咱们一步步拆解你的问题:你的HQL查询能成功执行,但在JSP页面显示分组后的Driver数据时抛出了NumberFormatException。这大概率是查询结果的结构和页面期望不匹配,或者实体映射/类型转换出了问题,下面详细分析:

先搞懂NumberFormatException的根源

这个异常本质是页面尝试把非数字类型的内容转成数字。比如你在JSP里写了${driver.id},但实际传给页面的对象根本不是Driver实体,而是一个Object数组,页面找不到getId()方法,底层会把数组当成字符串处理,转数字时直接炸锅。

你可能踩的常见坑:错误处理HQL查询结果

假设你写的HQL是这样的:

SELECT d.id, d.name FROM Driver d GROUP BY d.id, d.name

如果你的DAO层直接把查询结果强转成List<Driver>,那这就是核心错误!因为这种指定字段的HQL返回的不是Driver实体,而是Object数组(Object[])——数组的第一个元素是id,第二个是name。

当Controller把这个伪装成List<Driver>的List<Object[]>传到JSP,页面调用${driver.id}时,会尝试调用driver.getId(),但Object数组根本没有这个方法,最终触发类型转换异常,表现为NumberFormatException。

Hibernate Group By的正确用法

根据你的需求(获取Driver的id和name并分组),分两种场景处理:

场景1:返回完整Driver实体(当分组字段是主键)

如果你的分组是基于Driver的主键id(主键本身唯一,分组后和查询整个实体效果一致),可以直接查询实体:

FROM Driver d GROUP BY d.id

此时DAO层返回List<Driver>,Controller传到JSP后,正常用${driver.id}、${driver.name}即可,不会有类型问题。

场景2:返回指定字段(更高效,适合只需要部分数据的场景)

如果只需要id和name,或者要配合聚合函数(比如统计每个司机的订单数),推荐两种写法:

方式1:用Object数组接收结果

DAO层代码:

public List<Object[]> getDriverIdAndNameGrouped() {
    Session session = sessionFactory.getCurrentSession();
    Query query = session.createQuery("SELECT d.id, d.name FROM Driver d GROUP BY d.id, d.name");
    return query.list();
}

Controller把List<Object[]>传到JSP后,页面按数组索引取值:

<c:forEach items="${driverList}" var="driverArr">
    <tr>
        <td>${driverArr[0]}</td> <!-- 对应id -->
        <td>${driverArr[1]}</td> <!-- 对应name -->
    </tr>
</c:forEach>

方式2:用DTO构造函数映射(更优雅,避免数组索引混乱)

先创建一个DriverDTO类,专门用来接收查询结果:

public class DriverDTO {
    private Long id;
    private String name;

    // 必须和HQL里的字段顺序匹配的构造函数
    public DriverDTO(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    // 提供getter方法供EL表达式调用
    public Long getId() { return id; }
    public String getName() { return name; }
}

然后修改HQL,直接构造DTO:

SELECT new com.yourpackage.DriverDTO(d.id, d.name) FROM Driver d GROUP BY d.id, d.name

DAO层返回List<DriverDTO>,Controller传到JSP后,就可以像用实体一样调用属性:

<c:forEach items="${driverDTOList}" var="driver">
    <tr>
        <td>${driver.id}</td>
        <td>${driver.name}</td>
    </tr>
</c:forEach>

关键语法规则:Group By的约束

Hibernate的HQL遵循SQL的Group By规则:

  • Select语句中的非聚合字段,必须全部出现在Group By子句中(如果主键在Group By里,因为主键唯一确定其他字段,可省略其他字段)
  • 聚合函数(比如count(d.id)、sum(d.orderCount))不需要出现在Group By里

可能存在的映射错误

  1. 实体类id字段类型不匹配:比如数据库里id是INT/BIGINT,但实体类里id定义成String,或者反过来。当查询返回id后,JSP尝试转数字时就会抛出NumberFormatException。检查Driver实体类:
// 正确示例(数据库id为BIGINT时)
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; // 不要用String,除非数据库是字符型主键
  1. DAO层类型转换错误:强行把List<Object[]>转成List<Driver>,这会导致隐式的类型转换问题,在页面渲染时触发异常。
  2. JSP EL表达式错误:比如属性名大小写错误(比如把name写成Name),或者用实体的属性访问方式去访问Object数组。

快速排查步骤

  1. 在DAO层打印查询结果:遍历返回的List,打印每个元素的类型和值,确认是Driver实体还是Object数组。
  2. 检查JSP里的EL表达式,确保和返回的对象结构匹配。
  3. 验证Driver实体类的id字段类型和数据库字段类型完全一致。
  4. 确认HQL的Group By语法正确,Select的非聚合字段都在Group By里(或为主键)。

内容的提问来源于stack exchange,提问作者Vikas Biradargoudar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:08:18