简体   繁体   English

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

[英]@ManyToOne failed to lazy load when Hibernate second cache is enabled

I have created two really simple entities in my project:我在我的项目中创建了两个非常简单的实体:

@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;

    // ...
}

We've got an optional @ManyToOne relation from TestA to TestB.我们有一个从 TestA 到 TestB 的可选@ManyToOne关系。

When I'm trying to fetch a TestA instance, like this:当我尝试获取 TestA 实例时,如下所示:

entityManager.find(TestA.class, myId);

I'm getting two select: one for TestA, but also one for TestB, as it's eagerly loaded, which shouldn't happen.我得到了两个 select:一个用于 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=?

I tried all this combinations, even setting the relation as non-optional for the sake of testing:我尝试了所有这些组合,甚至为了测试将关系设置为非可选:

@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;

That doesn't change anything, TestB is still eagerly loaded.这并没有改变任何东西,TestB 仍然急切地加载。

However, when I'm disabling the second level cache in persistence.xml , like this:但是,当我在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>

Now TestB is lazy loaded, and I see the second select query only when I'm accessing TestA.getTestB().现在 TestB 是延迟加载的,只有在访问 TestA.getTestB() 时,我才会看到第二个 select 查询。

When I'm looking at the logs, I can see that, with second level cache enabled, Hibernate resolve testB to put it in cache:当我查看日志时,我可以看到,在启用二级缓存的情况下,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

I'm absolutely helpless here, as I cannot explain this behavior.我在这里绝对无助,因为我无法解释这种行为。 Is there a mistake or a bad practice somewhere in my code?我的代码中某处是否存在错误或不良做法?

I found it!我找到了!

To be fully JPA compliant, a proxy should be initialized when any of its fields is accessed, even the identifier (which was not the case with Hibernate, to avoid a query loop).为了完全符合 JPA,应在访问其任何字段时初始化代理,甚至是标识符(Hibernate 的情况并非如此,以避免查询循环)。

Since Hibernate 5.2.13 , there is a new option to fulfill this rule, hibernate.jpa.compliance.proxy , which is set by default to false in order to keep consistency with Hibernate previous behaviors. Since Hibernate 5.2.13 , there is a new option to fulfill this rule, hibernate.jpa.compliance.proxy , which is set by default to false in order to keep consistency with Hibernate previous behaviors.

But!但! Since Wildfly 14 , this option is set by default to true in the server context.Wildfly 14 开始,此选项在服务器上下文中默认设置为true My code is running on a WF18 instance, so it's the same.我的代码在 WF18 实例上运行,所以是一样的。

The solution was, like stated in this other question , to override the property in persistence.xml , resetting it to its default value, false :就像在另一个问题中所述,解决方案是覆盖persistence.xml中的属性,将其重置为默认值false

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 加载与Hibernate Envers的ManyToOne关系 - 渴望/懒惰? - Load ManyToOne Relation with Hibernate Envers - Eager/Lazy? 默认情况下是否启用Java Hibernate二级缓存? - Is Java Hibernate second level cache enabled by default? JPA休眠4延迟加载问题。 如何不急切地在ManyToOne中加载懒数据 - JPA hibernate 4 lazy load issue. How to load lazy data in ManyToOne without eager 休眠状态:ManyToOne关系失败 - Hibernate: Failed ManyToOne relationship 如何在Hibernate中将二级缓存用于延迟加载的集合? - How to use second level cache for lazy loaded collections in Hibernate? 在一个表上休眠两个 ManyToOne 关系,第一个获取 Eager,第二个 LAZY 加载 - Hibernate two ManyToOne relations on one Table, the first gets Eager and the second LAZY loaded 使用Kotlin进行Hibernate:@ManyToOne(fetch = FetchType.LAZY) - Hibernate with Kotlin: @ManyToOne(fetch = FetchType.LAZY) 休眠@MappedSuperclass @ManyToOne(fetch = FetchType.LAZY) - Hibernate @MappedSuperclass @ManyToOne(fetch=FetchType.LAZY) Hibernate ManyToOne FetchType.LAZY无法正常工作? - Hibernate ManyToOne FetchType.LAZY is not working? Hibernate @ManyToOne(fetch = FetchType.LAZY)被忽略 - Hibernate @ManyToOne(fetch = FetchType.LAZY) ignored
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM