gpt4 book ai didi

java - @ManyToOne 在启用 Hibernate 二级缓存时延迟加载失败

转载 作者:行者123 更新时间:2023-12-04 15:28:31 24 4
gpt4 key购买 nike

我在我的项目中创建了两个非常简单的实体:

@Entity
@Access(FIELD)
public class TestA implements Serializable
{
@Id
private UUID id;
@Version
private Long hVersion;

@ManyToOne(fetch = FetchType.LAZY, optional = true)
private TestB testB;

// ...
}


@Entity
@Access(FIELD)
public class TestB implements Serializable
{
@Id
private UUID id;
@Version
private Long hVersion;

// ...
}

我们有一个从 TestA 到 TestB 的可选 @ManyToOne 关系。

当我尝试获取 TestA 实例时,如下所示:

entityManager.find(TestA.class, myId);

我得到两个选择:一个用于 TestA,还有一个用于 TestB,因为它是急切加载的,这是不应该发生的。

Hibernate: select testa0_.id as id1_20_0_, testa0_.h_version as h_versio2_20_0_, testa0_.test_b_id as test_b_i3_20_0_ from test_a testa0_ where testa0_.id=?
Hibernate: select testb0_.id as id1_21_0_, testb0_.h_version as h_versio2_21_0_ from test_b testb0_ where testb0_.id=?

我尝试了所有这些组合,甚至为了测试将关系设置为非可选:

@ManyToOne(fetch = FetchType.LAZY, optional = true)
private TestB testB;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
private TestB testB;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@LazyToOne(LazyToOneOption.PROXY)
private TestB testB;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@LazyToOne(LazyToOneOption.NO_PROXY)
private TestB testB;

这并没有改变任何东西,TestB 仍然被急切加载。

但是,当我在 persistence.xml 中禁用二级缓存时,如下所示:

<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.debug" value="false" />
<property name="hibernate.cache.use_second_level_cache" value="false" />
<property name="hibernate.cache.use_query_cache" value="false" />
</properties>

现在 TestB 是延迟加载的,只有在访问 TestA.getTestB() 时我才会看到第二个选择查询。

当我查看日志时,我可以看到,在启用二级缓存的情况下,Hibernate 解析 testB 以将其放入缓存中:

DEBUG [org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl] (default task-4) Hibernate RegisteredSynchronization successfully registered with JTA platform
DEBUG [org.hibernate.SQL] (default task-4) select testa0_.id as id1_20_0_, testa0_.h_version as h_versio2_20_0_, testa0_.test_b_id as test_b_i3_20_0_ from test_a testa0_ where testa0_.id=?
DEBUG [org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl] (default task-4) Starting ResultSet row #0
DEBUG [org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl] (default task-4) On call to EntityIdentifierReaderImpl#resolve, EntityKey was already known; should only happen on root returns with an optional identifier specified
DEBUG [org.hibernate.engine.internal.TwoPhaseLoad] (default task-4) Resolving associations for [com.monde3.lpt.veriqualis.model.test.TestA#00000000-9999-1111-1111-000000000001]
DEBUG [org.hibernate.engine.internal.TwoPhaseLoad] (default task-4) Adding entity to second-level cache: [com.monde3.lpt.veriqualis.model.test.TestA#00000000-9999-1111-1111-000000000001]
DEBUG [org.hibernate.internal.SessionImpl] (default task-4) Initializing proxy: [com.monde3.lpt.veriqualis.model.test.TestB#00000000-9999-1111-1111-000000000002]
DEBUG [org.hibernate.SQL] (default task-4) select testb0_.id as id1_21_0_, testb0_.h_version as h_versio2_21_0_ from test_b testb0_ where testb0_.id=?
DEBUG [org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl] (default task-4) Starting ResultSet row #0
DEBUG [org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl] (default task-4) On call to EntityIdentifierReaderImpl#resolve, EntityKey was already known; should only happen on root returns with an optional identifier specified
DEBUG [org.hibernate.engine.internal.TwoPhaseLoad] (default task-4) Resolving associations for [com.monde3.lpt.veriqualis.model.test.TestB#00000000-9999-1111-1111-000000000002]
DEBUG [org.hibernate.engine.internal.TwoPhaseLoad] (default task-4) Adding entity to second-level cache: [com.monde3.lpt.veriqualis.model.test.TestB#00000000-9999-1111-1111-000000000002]
DEBUG [org.hibernate.engine.internal.TwoPhaseLoad] (default task-4) Done materializing entity [com.monde3.lpt.veriqualis.model.test.TestB#00000000-9999-1111-1111-000000000002]
DEBUG [org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl] (default task-4) Skipping aggressive release due to registered resources
DEBUG [org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader] (default task-4) Done entity load : com.monde3.lpt.veriqualis.model.test.TestB#00000000-9999-1111-1111-000000000002

我在这里完全无助,因为我无法解释这种行为。我的代码中是否存在错误或不良做法?

最佳答案

我找到了!

要完全符合 JPA,应在访问其任何字段时初始化代理,甚至是标识符(Hibernate 不是这种情况,以避免查询循环)。

Hibernate 5.2.13 ,有一个新的选项来满足这个规则,hibernate.jpa.compliance.proxy ,默认设置为 false 以与 Hibernate 以前的行为保持一致。

但是!自 Wildfly 14 ,此选项在服务器上下文中默认设置为 true。我的代码在 WF18 实例上运行,所以它是一样的。

解决方案如 this other question 中所述, 覆盖 persistence.xml 中的属性,将其重置为其默认值 false:

<property name="hibernate.jpa.compliance.proxy" value="false" />

关于java - @ManyToOne 在启用 Hibernate 二级缓存时延迟加载失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61752552/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com