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

Hibernate 6.2为何将复合主键的JPQL等于操作转为IN子查询?

问题背景

我有一个基于Spring Boot 3.1.1 / Hibernate 6.2的应用,使用以下依赖的ojdbc8驱动连接Oracle 12c数据库:

<dependency>
    <groupId>com.oracle.database.jdbc</groupId>
    <artifactId>ojdbc8</artifactId>
    <scope>runtime</scope>
</dependency>

该应用包含如下仓库接口与实体类:

public interface SomeEntityRepository extends Repository<SomeEntity, SomeEntityId> {
  @Query("""
      FROM SomeEntity
      WHERE id = :id
        AND description is not null
      """)
  Optional<SomeEntity> find(SomeEntityId id);
}
@Embeddable
public class SomeEntityId {
    private Long idX;
    private Long idY;
    private Long idZ;
}
@Entity
public class SomeEntity {
    @EmbeddedId
    private SomeEntityId id;
    private String description;
}

执行find查询时,Hibernate 6.2将JPQL翻译为如下SQL:

Hibernate: 
    select
        s1_0.idx,
        s1_0.idy,
        s1_0.idz,
        s1_0.description 
    from
        some_entity s1_0 
    where
        (
            s1_0.idx,s1_0.idy,s1_0.idz
        ) in (select
            ?,?,? 
        from
            dual) 
        and s1_0.description is not null

而在Spring Boot 2.7.13 / Hibernate 5.6环境中执行相同代码,JPQL会被翻译为逐个字段比较的SQL:

Hibernate: 
    select
        someentity0_.idx as idx1_1_,
        someentity0_.idy as idy2_1_,
        someentity0_.idz as idz3_1_,
        someentity0_.description as description4_1_ 
    from
        some_entity someentity0_ 
    where
        someentity0_.idx=? 
        and someentity0_.idy=? 
        and someentity0_.idz=? 
        and (
            someentity0_.description is not null
        )

请问为何Hibernate 6.2会将复合主键的JPQL等于操作转为IN子查询,而非像Hibernate 5那样逐个字段比较?

原因分析

这是Hibernate 6.x为适配**SQL标准中的行值表达式(Row Value Expression)**所做的查询优化与语法调整,具体原因如下:

  • 对齐SQL标准:行值表达式(如(col1, col2, col3) = (val1, val2, val3))是SQL官方标准支持的语法,Hibernate 6.x优先生成贴合标准的SQL,替代了Hibernate 5.x时代拆分复合主键逐个字段比较的自定义逻辑。
  • 兼容Oracle特性:虽然Oracle 12c本身支持直接的行值相等比较,但Hibernate 6.x考虑到部分Oracle版本或驱动的兼容性问题,选择用IN子查询+dual表的方式模拟行值比较——这种写法在全版本Oracle中都能稳定运行,避免了直接使用行值表达式可能出现的兼容性报错。
  • 统一查询翻译逻辑:Hibernate 6.x重构了核心查询翻译引擎,针对复合主键的相等判断,统一采用行值表达式的思路处理,不管是单个主键还是批量主键查询,翻译逻辑更一致,减少了不同场景下的语法分支,降低了维护成本。

需要说明的是,这种SQL写法的差异不会影响查询结果,Oracle的查询优化器通常能将IN子查询的写法优化到和逐个字段比较相同的执行计划,性能上不会有明显差异。

内容的提问来源于stack exchange,提问作者Alexandre Almeida

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 05:02:30