如果从数据库加载两次,hibernate 是否会加载同一实例的两个单独副本?
不,它不会在同一个会话中两次加载同一个对象(为了我们的理智)。
我创建了一个简单的Spring Boot 项目 https://github.com/gabrielgiussi/so-31045875/tree/1.2看到这个。
EntityA#setOfB(B1,B2)
EntityB#setOfA(A1)
通过 ID 将 EntityA 1 和 EntityB 加载到 Session 后,我们强制 A1.setOfB 初始化。
在下面的日志中我们可以看到,虽然它必须查询集合以获得两行(B1和B2),但它只会隐藏一个对象(B2),因为B1是在会话缓存中找到的。请参阅测试 1 (mvn spring-boot:run -Drun.arguments="1")
DEBUG 6452 --- [ main] o.g.hiplay.app.HibernateService : ########## Retrieving A1's set of B ##########
DEBUG 6452 --- [ main] org.hibernate.SQL : select setofb0_.id_a as id_a1_0_0_, setofb0_.id_b as id_b2_2_0_, entityb1_.id as id1_1_1_, entityb1_.description as descript2_1_1_ from relations setofb0_ inner join entityb entityb1_ on setofb0_.id_b=entityb1_.id where setofb0_.id_a=?
TRACE 6452 --- [ main] o.h.l.p.e.i.AbstractLoadPlanBasedLoader : Bound [2] parameters total
DEBUG 6452 --- [ main] o.h.l.p.e.p.i.ResultSetProcessorImpl : Preparing collection intializer : [oss.gabrielgiussi.hiplay.entities.EntityA.setOfB#1]
TRACE 6452 --- [ main] o.h.e.loading.internal.LoadContexts : Constructing collection load context for result set [rs3: org.h2.result.LocalResult@5c99abd7 columns: 4 rows: 2 pos: -1]
TRACE 6452 --- [ main] o.h.e.l.internal.CollectionLoadContext : Starting attempt to find loading collection [[oss.gabrielgiussi.hiplay.entities.EntityA.setOfB#1]]
TRACE 6452 --- [ main] o.h.e.l.internal.CollectionLoadContext : Collection not yet initialized; initializing
TRACE 6452 --- [ main] o.h.l.p.e.p.i.ResultSetProcessorImpl : Processing result set
DEBUG 6452 --- [ main] o.h.l.p.e.p.i.ResultSetProcessorImpl : Starting ResultSet row #0
DEBUG 6452 --- [ main] e.p.i.CollectionReferenceInitializerImpl : Found row of collection: [oss.gabrielgiussi.hiplay.entities.EntityA.setOfB#1]
TRACE 6452 --- [ main] o.h.e.l.internal.CollectionLoadContext : Starting attempt to find loading collection [[oss.gabrielgiussi.hiplay.entities.EntityA.setOfB#1]]
TRACE 6452 --- [ main] o.h.e.loading.internal.LoadContexts : Attempting to locate loading collection entry [CollectionKey[oss.gabrielgiussi.hiplay.entities.EntityA.setOfB#1]] in any result-set context
TRACE 6452 --- [ main] o.h.e.loading.internal.LoadContexts : Collection [CollectionKey[oss.gabrielgiussi.hiplay.entities.EntityA.setOfB#1]] located in load context
TRACE 6452 --- [ main] o.h.e.l.internal.CollectionLoadContext : Found loading collection bound to current result set processing; reading row
TRACE 6452 --- [ main] o.h.e.internal.DefaultLoadEventListener : Loading entity: [oss.gabrielgiussi.hiplay.entities.EntityB#1]
TRACE 6452 --- [ main] o.h.e.internal.DefaultLoadEventListener : Attempting to resolve: [oss.gabrielgiussi.hiplay.entities.EntityB#1]
TRACE 6452 --- [ main] o.h.e.internal.DefaultLoadEventListener : Resolved object in session cache: [oss.gabrielgiussi.hiplay.entities.EntityB#1]
DEBUG 6452 --- [ main] o.h.l.p.e.p.i.ResultSetProcessorImpl : Starting ResultSet row #1
TRACE 6452 --- [ main] l.p.e.p.i.EntityReferenceInitializerImpl : hydrating entity state
TRACE 6452 --- [ main] l.p.e.p.i.EntityReferenceInitializerImpl : Initializing object from ResultSet: [oss.gabrielgiussi.hiplay.entities.EntityB#2]
TRACE 6452 --- [ main] o.h.p.entity.AbstractEntityPersister : Hydrating entity: [oss.gabrielgiussi.hiplay.entities.EntityB#2]
DEBUG 6452 --- [ main] e.p.i.CollectionReferenceInitializerImpl : Found row of collection: [oss.gabrielgiussi.hiplay.entities.EntityA.setOfB#1]
TRACE 6452 --- [ main] o.h.e.l.internal.CollectionLoadContext : Starting attempt to find loading collection [[oss.gabrielgiussi.hiplay.entities.EntityA.setOfB#1]]
TRACE 6452 --- [ main] o.h.e.loading.internal.LoadContexts : Attempting to locate loading collection entry [CollectionKey[oss.gabrielgiussi.hiplay.entities.EntityA.setOfB#1]] in any result-set context
TRACE 6452 --- [ main] o.h.e.loading.internal.LoadContexts : Collection [CollectionKey[oss.gabrielgiussi.hiplay.entities.EntityA.setOfB#1]] located in load context
TRACE 6452 --- [ main] o.h.e.l.internal.CollectionLoadContext : Found loading collection bound to current result set processing; reading row
TRACE 6452 --- [ main] o.h.e.internal.DefaultLoadEventListener : Loading entity: [oss.gabrielgiussi.hiplay.entities.EntityB#2]
TRACE 6452 --- [ main] o.h.e.internal.DefaultLoadEventListener : Attempting to resolve: [oss.gabrielgiussi.hiplay.entities.EntityB#2]
TRACE 6452 --- [ main] o.h.e.internal.DefaultLoadEventListener : Resolved object in session cache: [oss.gabrielgiussi.hiplay.entities.EntityB#2]
TRACE 6452 --- [ main] o.h.l.p.e.p.i.ResultSetProcessorImpl : Done processing result set (2 rows)
TRACE 6452 --- [ main] o.h.l.p.e.p.internal.AbstractRowReader : Total objects hydrated: 1
DEBUG 6452 --- [ main] o.h.engine.internal.TwoPhaseLoad : Resolving associations for [oss.gabrielgiussi.hiplay.entities.EntityB#2]
TRACE 6452 --- [ main] o.h.e.loading.internal.LoadContexts : Attempting to locate loading collection entry [CollectionKey[oss.gabrielgiussi.hiplay.entities.EntityB.setOfA#2]] in any result-set context
TRACE 6452 --- [ main] o.h.e.loading.internal.LoadContexts : Collection [CollectionKey[oss.gabrielgiussi.hiplay.entities.EntityB.setOfA#2]] not located in load context
TRACE 6452 --- [ main] org.hibernate.type.CollectionType : Created collection wrapper: [oss.gabrielgiussi.hiplay.entities.EntityB.setOfA#2]
DEBUG 6452 --- [ main] o.h.engine.internal.TwoPhaseLoad : Done materializing entity [oss.gabrielgiussi.hiplay.entities.EntityB#2]
TRACE 6452 --- [ main] o.h.e.loading.internal.LoadContexts : Attempting to locate loading collection entry [CollectionKey[oss.gabrielgiussi.hiplay.entities.EntityA.setOfB#1]] in any result-set context
TRACE 6452 --- [ main] o.h.e.loading.internal.LoadContexts : Collection [CollectionKey[oss.gabrielgiussi.hiplay.entities.EntityA.setOfB#1]] located in load context
TRACE 6452 --- [ main] o.h.e.l.internal.CollectionLoadContext : Removing collection load entry [org.hibernate.engine.loading.internal.LoadingCollectionEntry<rs=rs3: org.h2.result.LocalResult@5c99abd7 columns: 4 rows: 2 pos: 2, coll=[oss.gabrielgiussi.hiplay.entities.EntityA.setOfB#1]>@131c8e88]
DEBUG 6452 --- [ main] o.h.e.l.internal.CollectionLoadContext : 1 collections were found in result set for role: oss.gabrielgiussi.hiplay.entities.EntityA.setOfB
TRACE 6452 --- [ main] o.h.e.l.internal.CollectionLoadContext : Ending loading collection [org.hibernate.engine.loading.internal.LoadingCollectionEntry<rs=rs3: org.h2.result.LocalResult@5c99abd7 columns: 4 rows: 2 pos: 2, coll=[oss.gabrielgiussi.hiplay.entities.EntityA.setOfB#1]>@131c8e88]
DEBUG 6452 --- [ main] o.h.e.l.internal.CollectionLoadContext : Collection fully initialized: [oss.gabrielgiussi.hiplay.entities.EntityA.setOfB#1]
DEBUG 6452 --- [ main] o.h.e.l.internal.CollectionLoadContext : 1 collections initialized for role: oss.gabrielgiussi.hiplay.entities.EntityA.setOfB
TRACE 6452 --- [ main] o.h.e.i.StatefulPersistenceContext : Initializing non-lazy collections
DEBUG 6452 --- [ main] o.g.hiplay.app.HibernateService : ########## The object hasn't been loaded twice ##########
Hibernate 检查是否补水对象 https://github.com/hibernate/hibernate-orm/blob/master/hibernate-core/src/main/java/org/hibernate/loader/Loader.java#L1542已经在会话缓存中询问 StatefulPersistenceContext https://github.com/hibernate/hibernate-orm/blob/5.0/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java#L598
我现在期望的是实体 B 的实例 bB 也已完全初始化,但不,它没有,当我引用实体 B 的包含实体 A 的实例 aA 的集合时,我会遇到延迟初始化异常。
真正未初始化的是 bB 的 A 集。在执行以下操作后:
EntityA aA = session.get("A",a)
aA.setOfB.size() // 强制初始化惰性集合。此时 bB 已被水合并放入内存中,但他的 A 集合尚未初始化。
如果您尝试访问集合的元素,Hibernate 需要初始化该集合(到目前为止,它所拥有的只是一个代理,具有在需要时从数据库加载集合的智能,例如询问元素或集合的大小) 。请参阅测试 3 (mvn spring-boot:run -Drun.arguments="2")
// outside of the transaction
EntityB bB = aA.setOfB().get(0)
bB.setOfA().size() // LazyInitializationExample
如果您处于事务内部,则集合将被初始化,并且将再次从基中检索与 aA 对应的行,但它不会被水化。请参阅测试 3 (mvn spring-boot:run -Drun.arguments="3")