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

Hibernate CriteriaBuilder时间类型比较报错排查求助

问题分析与解决方案

你的问题根源很明确:Hibernate的criteriaBuilder.currentTime()生成的是SQL DATETIME类型的表达式,但你的数据库字段是TIME类型,两者在MSSQL中无法直接用比较运算符(>=、<=等)进行比较,所以抛出了类型不兼容的错误。

你添加的sendTimeAsDateTime=false参数其实作用是告诉JDBC驱动将Java的java.sql.Time对象以SQL TIME类型发送给数据库,但它无法改变Hibernate生成的SQL表达式中currentTime()对应的类型——这个方法默认生成的是包含日期和时间的DATETIME类型,所以这个参数对你的问题没有帮助。

下面给你两种可行的解决方案:


方案一:在Criteria查询中转换当前时间的SQL类型

直接在查询里用MSSQL的CONVERT函数,把currentTime()生成的DATETIME转成TIME类型,确保比较两边类型一致:

@Override
public Long countAll(boolean isAvailable) {
    CriteriaQuery<Long> query = criteriaBuilder.createQuery(Long.class);
    Root<ParkingLotEntity> root = query.from(ParkingLotEntity.class);
    
    // 使用MSSQL的CONVERT函数将当前时间转为TIME类型
    Expression<Time> currentTime = criteriaBuilder.function(
        "CONVERT", 
        Time.class, 
        criteriaBuilder.literal("time"), 
        criteriaBuilder.currentTime()
    );

    Predicate predicate;
    if (isAvailable) {
        predicate = criteriaBuilder.and(
            criteriaBuilder.equal(root.get(ParkingLotEntity_.isAvailable), true),
            criteriaBuilder.greaterThanOrEqualTo(root.get(ParkingLotEntity_.openingHour), currentTime),
            criteriaBuilder.lessThanOrEqualTo(root.get(ParkingLotEntity_.closingHour), currentTime)
        );
    } else {
        predicate = criteriaBuilder.or(
            criteriaBuilder.equal(root.get(ParkingLotEntity_.isAvailable), false),
            criteriaBuilder.lessThan(root.get(ParkingLotEntity_.openingHour), currentTime),
            criteriaBuilder.greaterThan(root.get(ParkingLotEntity_.closingHour), currentTime)
        );
    }

    return entityManager.createQuery(query
            .select(criteriaBuilder.count(root))
            .where(predicate))
            .getSingleResult();
}

方案二:在Java端生成TIME类型的当前时间参数

另一种更直观的方式是在Java代码中获取当前时间的时间部分,转换为java.sql.Time对象,然后作为参数传入查询,这样Hibernate会生成参数化查询,自动匹配数据库的TIME类型:

@Override
public Long countAll(boolean isAvailable) {
    CriteriaQuery<Long> query = criteriaBuilder.createQuery(Long.class);
    Root<ParkingLotEntity> root = query.from(ParkingLotEntity.class);
    
    // 提取当前时间的时分秒部分,转为java.sql.Time
    Time currentSqlTime = Time.valueOf(LocalTime.now());

    Predicate predicate;
    if (isAvailable) {
        predicate = criteriaBuilder.and(
            criteriaBuilder.equal(root.get(ParkingLotEntity_.isAvailable), true),
            criteriaBuilder.greaterThanOrEqualTo(root.get(ParkingLotEntity_.openingHour), currentSqlTime),
            criteriaBuilder.lessThanOrEqualTo(root.get(ParkingLotEntity_.closingHour), currentSqlTime)
        );
    } else {
        predicate = criteriaBuilder.or(
            criteriaBuilder.equal(root.get(ParkingLotEntity_.isAvailable), false),
            criteriaBuilder.lessThan(root.get(ParkingLotEntity_.openingHour), currentSqlTime),
            criteriaBuilder.greaterThan(root.get(ParkingLotEntity_.closingHour), currentSqlTime)
        );
    }

    return entityManager.createQuery(query
            .select(criteriaBuilder.count(root))
            .where(predicate))
            .getSingleResult();
}

额外优化建议

为了避免Hibernate映射时的类型歧义,你可以在实体字段上明确指定数据库列类型,确保映射完全匹配:

@Column(name = "[OPENING_HOUR]", nullable = false, columnDefinition = "time")
private Time openingHour;

@Column(name = "[CLOSING_HOUR]", nullable = false, columnDefinition = "time")
private Time closingHour;

这样可以确保Hibernate不会将TIME字段误映射为其他类型,减少隐式转换带来的问题。

内容的提问来源于stack exchange,提问作者Huỳnh Thanh Bình

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 08:12:45