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

迁移Spring Boot3后JdbcTypeRecommendationException异常求助

Spring Boot 3(Hibernate 6)迁移后Criteria API查询报错问题

问题背景

已全网搜索相关解决方案但均无效,代码在迁移到Spring Boot 3(Hibernate 6)前运行正常,排查后定位到Criteria API中的代码引发异常。

简化版实体类代码

@Entity
@Table(name = "msg")
public class InternalMessage implements Serializable {
    private static final long serialVersionUID = 3768430013233258L;

    @PrePersist
    public void genTicketId() {
        // something
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", unique = true)
    private Long id;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "internal_msg_parent_fk", nullable = true)
    private InternalMessage parent = null;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
    private List<InternalMessage> childMessages = new ArrayList<>();
}

环境信息

Mysql: 8.0.33
Spring boot: 3.3.3
Vscode 1.92.2
gradle: 8.10

无论在VSCode调试模式还是通过命令行./gradlew bootRun运行,结果一致。

异常触发代码

public Predicate toPredicate(Root<InternalMessage> root, CriteriaQuery<?> query,
                CriteriaBuilder criteriaBuilder) {
            List<Predicate> predicates = new ArrayList<>();

            if (search == null || search.trim().isEmpty()) {
                // 此处代码引发异常
                Expression<InternalMessage> parent = root.get("parent").as(InternalMessage.class);
                Predicate p = criteriaBuilder.isNull(parent);
                predicates.add(p);
                query.distinct(true);
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            } else {
                // 此部分代码正常运行
            }
        }

具体异常行:

Expression<InternalMessage> parent = root.get("parent").as(InternalMessage.class);

该行代码在旧版Spring Boot/Hibernate中运行正常,请问存在什么问题?


问题原因及解决方案

原因分析

Hibernate 6(对应JPA 3.0)对Criteria API的类型处理做了严格规范:

  • root.get("parent")返回的Path<InternalMessage>本身已经是正确的关联类型,无需再调用as(InternalMessage.class)做冗余类型转换
  • 旧版Hibernate对类型校验较宽松,允许这种不必要的强转,但Hibernate 6会判定该操作属于非法类型转换,触发异常

解决方案

直接移除as(InternalMessage.class)的类型转换,修改后代码如下:

// 简化写法
predicates.add(criteriaBuilder.isNull(root.get("parent")));

// 或者分步写法
Path<InternalMessage> parent = root.get("parent");
Predicate p = criteriaBuilder.isNull(parent);
predicates.add(p);

修改后的代码既符合JPA 3.0规范,也适配Hibernate 6的类型校验逻辑,同时保留原有查询逻辑。


内容的提问来源于stack exchange,提问作者The MW

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 02:37:04