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.
When I'm trying to fetch a TestA instance, like this:
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.
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.
However, when I'm disabling the second level cache in persistence.xml
, like this:
<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().
When I'm looking at the logs, I can see that, with second level cache enabled, Hibernate resolve testB to put it in cache:
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?