2015-06-25 46 views
1

我知道關於延遲加載的SO有很多不同的問題,但我的一個有點不同。如果hibernate從數據庫加載兩次,它會加載兩個相同實例的單獨副本嗎?

假設我有一個實體A,其中我有實體B的集合。同樣,在實體B中,我有集合A.在這兩種情況下,都使用lazy =「true」選項。

實體A的instace AA具有 - >Set<B> ===(這個集合包含實體B的實例BB)

實體B的instace BB具有 - >Set<A> ===(該集包含實體A的實例aA)

現在,如果我加載實體A的集合(即Set<B>)。它現在已初始化,即完成A的包含集合的aA實例。我期望的是實體B的實例bB也被完全初始化,但是不,它不是,當我引用具有實體A的實例aA的實體B的集合時,我得到了懶惰初始化異常。

如果從數據庫中加載兩次,hibernate會加載兩個相同實例的單獨副本嗎?如果是這樣,有沒有辦法在會話中同步所有副本中的更改?

希望我足夠清楚,並沒有把事情搞亂凌亂的信息:)

+1

用'懶惰= TRUE',裝載'A'將懶惰地加載'B',但在 'B' ,只有標識符會被加載'(ie b。id)',但我們需要使用'HIbernate.intialize(a.getB())'分別初始化lzy集合;' –

+1

這很可能是一個性能低下並且附加值不高的命中。 – Kayaman

+0

你能解釋一下你爲什麼這麼期待嗎?如果我明白了,你期望如果有一件事是懶惰地初始化的,那麼整個會話中的其他事情應該立即初始化? –

回答

1

流程是這樣的:

  1. 您加載aAaB。他們的收藏是懶惰和代理。
  2. 您初始化aA的集合。其中包含實例aB,它與您之前已經加載的相同(同一個Java對象)。 aB實例中的集合尚未初始化;你沒有訪問它,所以Hibernate不會浪費時間來初始化它。目前,aAaB收藏的成員,在此會話中未知。
  3. 您訪問(初始化)aB的集合。其中包含實例aA,它與您之前已經加載的相同(同一個Java對象)。

如您所見,當前會話(持久性上下文)中沒有重複項。可能有不同的代理/集合,但它們都委託給/包含相同的實體實例。

0

Hibernate以及JPA保證會話中不會有兩個副本(實體管理器)。 但是,通過清除會話或直接將實體從會話(session.evict())中分離並再次加載,您總是可以在內存中獲取一個對象的兩個或多個副本。 所以你可以認爲只有一個實體副本是存在的。 只有該副本與數據庫同步。 您可以通過調用session.merge()再次重新掛接分離的實體,但請注意,此方法始終返回實體的副本,可能與原始副本不同。 如果有一個實體的持久副本,你只需要獲取它。 BWT,要確定實體是否持久,您可以撥打session.contains()

Hibernate中有幾個錯誤有時會導致實體的兩個或多個持久性副本出現在會話中,與繼承有關。 首先,你加載一個實體的正常副本。 其次,您加載了另一個實體,該實體與第一個實體具有惰性@ManyToOne關係。 第三,你按照參考,並獲得第一個實體的另一個副本! 因此,不要在Hibernate中使用繼承,也不要使用Hibernate。 考慮使用EclipseLink,因爲它沒有這樣的錯誤。

+0

考慮重新命名'總是返回一個新的副本',因爲它不會執行這個'always',並且沒有指定該實例是否是'new'。 –

+0

@SteveC是的,你是對的。我的意思是合併返回的實例可能與原始實例不同,並且應該始終使用新實例而不是舊實例,因爲舊的實例可能會被分離。當然,Hibernate可以返回相同的實例,創建一個新實例或返回現有的持久實體。 –

2

如果hibernate從數據庫中加載兩次,是否會加載同一實例的兩個單獨副本?

不,它不會在同一會話中兩次加載同一個對象(出於我們的理智)。

我創建了一個簡單的Spring Boot project來查看此信息。

EntityA#setOfB(B1,B2) 
EntityB#setOfA(A1) 

負載EntityA 1和EntityB到會議通過ID後,我們強迫A1.setOfB初始化。 在下面的日誌中我們可以看到,儘管它必須查詢獲得兩行的集合(B1 & B2),但它只會隱藏一個對象(B2),因爲在會話緩存中找到了B1。見測試1(MVN春季啓動:運行-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: [email protected] 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: [email protected] 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: [email protected] 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 ########## 

休眠檢查是否Object to hydrate已經在會話緩存asking to the StatefulPersistenceContext

我現在想到的是實體B的實例bB也被完全初始化,但是不,它不是,當我引用具有實體A的實例aA的實體B的集合時,我得到延遲初始化異常。

什麼是真正的初始化是BB的集合A的做這樣的事情後:

EntityA AA = session.get( 「A」,A) aA.setOfB.size()//初始化力懶惰的收集。在這一點上,bB是水合性的並且被記憶,但是他收集的A是不合資格的。

enter image description here

如果您嘗試訪問集合Hibernate需要初始化集合(的元素都具有到現在爲止是與負載的智能在需要時從數據庫中的集合,例如請求代理一個元素或集合的大小)。見試驗3(MVN春季啓動:運行-Drun.arguments =「2」)

// outside of the transaction 
EntityB bB = aA.setOfB().get(0) 
bB.setOfA().size() // LazyInitializationExample 

enter image description here

如果你是一個交易的集合將被初始化以及對應於AA行內會再次從基地取回,但不會被水合。見試驗3(MVN彈簧引導:運行-Drun.arguments = 「3」)

enter image description here