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

Hibernate @NotFound无匹配记录时关联查询结果异常求助

问题解决:Hibernate加载关联集合时的间歇性空值问题

依赖配置

<properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <spring.version>5.3.29</spring.version>
    <hibernate.version>5.3.20.Final</hibernate.version>
    <oracle.version>19.3.0.0</oracle.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-orm</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>${spring.version}</version>
        <scope>test</scope>
    </dependency>
    
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>${hibernate.version}</version>
    </dependency>

    <!-- JDBC driver -->
    <dependency>
        <groupId>com.oracle.ojdbc</groupId>
        <artifactId>ojdbc10</artifactId>
        <version>${oracle.version}</version>
        <exclusions>
            <exclusion>
                <groupId>com.oracle.ojdbc</groupId>
                <artifactId>ucp</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>

实体关联关系

三个实体通过col_2关联,数据库无关联约束:

@Table(name = "test_a")
@Entity
public class A implements Serializable {
    @Id
    @Column(name = "col_1")
    private String col1;

    @Column(name = "col_2")
    private String col2;

    @OneToOne
    @JoinColumn(name = "col_2", referencedColumnName = "col_2",insertable = false,updatable = false)
    @NotFound(action = NotFoundAction.IGNORE)
    private B b;

    @OneToMany
    @JoinColumn(name = "col_2", referencedColumnName = "col_2", insertable = false, updatable = false)
    private List<C> cs;
}

@Table(name = "test_b")
@Entity
public class B implements Serializable {
    @Id
    @Column(name = "col_1")
    private String col1;

    @Column(name = "col_2")
    private String col2;
}

@Table(name = "test_c")
@Entity
public class C implements Serializable {
    @Id
    @Column(name = "col_1")
    private String col1;

    @Column(name = "col_2")
    private String col2;
}

问题现象

加载A实体时,当关联的B实体无匹配记录,A的cs集合间歇性为空。异常场景下,系统会多次查询test_b表,最终查询test_c时绑定null作为参数。

问题原因

这是Hibernate 5.x版本中,处理@NotFound(action = NotFoundAction.IGNORE)与延迟加载集合时的已知行为:
当Hibernate加载A的延迟集合cs时,会尝试复用之前查询B关联的上下文。如果B不存在,@NotFound(IGNORE)会将B设为null,此时Hibernate错误地将null作为col_2的参数传递给cs的查询,而非使用A自身的col2值。这种间歇性源于Hibernate缓存和查询计划的不确定性。

解决方案

方案1:显式指定集合查询的Fetch模式

修改A实体中cs字段的注解,添加@Fetch(FetchMode.SELECT),强制Hibernate在查询集合时直接使用A实体的col2值,而非复用关联查询的上下文:

@OneToMany
@JoinColumn(name = "col_2", referencedColumnName = "col_2", insertable = false, updatable = false)
@Fetch(FetchMode.SELECT)
private List<C> cs;

方案2:使用JPQL显式控制加载逻辑

在查询A实体时,通过JPQL显式指定加载cs集合,确保参数从A的col2获取:

SELECT a FROM A a LEFT JOIN FETCH a.cs WHERE a.col1 = :col1

关于双向关联生效的原因

配置双向关联后,Hibernate会明确从A实体的col2属性获取关联参数,而非依赖B关联查询的结果,因此避免了B不存在时的null值传递问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 13:02:06