首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >@ManyToOne在启用Hibernate第二个缓存时未能延迟加载

@ManyToOne在启用Hibernate第二个缓存时未能延迟加载
EN

Stack Overflow用户
提问于 2020-05-12 13:08:35
回答 1查看 425关注 0票数 3

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

代码语言:javascript
复制
@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;

    // ...
}

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

当我试图获取一个TestA实例时,如下所示:

代码语言:javascript
复制
entityManager.find(TestA.class, myId);

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

代码语言:javascript
复制
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=?

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

代码语言:javascript
复制
@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中禁用第二级缓存时,如下所示:

代码语言:javascript
复制
<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()时,我才会看到第二个select查询。

当我查看日志时,我可以看到,启用了二级缓存后,Hibernate解析testB将其放入缓存中:

代码语言:javascript
复制
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

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-13 08:01:27

我找到了!

为了完全兼容JPA,应该在访问代理的任何字段时初始化代理,即使是标识符( Hibernate的情况不是这样,以避免查询循环)。

由于冬眠5.2.13,有一个新的选项来实现这个规则,hibernate.jpa.compliance.proxy,默认情况下设置为false,以保持与Hibernate先前行为的一致性。

但!由于野蝇14,此选项默认设置为服务器上下文中的true。我的代码运行在一个WF18实例上,所以它是相同的。

另一个问题中所述,解决方案是覆盖persistence.xml中的属性,将其重置为默认值false

代码语言:javascript
复制
<property name="hibernate.jpa.compliance.proxy" value="false" />
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61752552

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档