[英]Hibernate lazy loading for reverse one to one workaround - how does this work?
今天我遇到問題,延遲加載在使用映射集合時無法正常工作。 我發現這篇優秀的文章似乎解決了這個問題
http://justonjava.blogspot.co.uk/2010/09/lazy-one-to-one-and-one-to-many.html
我不明白的一件事是使用FieldHandled的解決方法是如何工作的。 任何人都可以幫我理解這個嗎? 有問題的代碼如下(從鏈接上的示例中復制):
@Entity
public class Animal implements FieldHandled {
private Person owner;
private FieldHandler fieldHandler;
@OneToOne(fetch = FetchType.LAZY, optional = true, mappedBy = "animal")
@LazyToOne(LazyToOneOption.NO_PROXY)
public Person getOwner() {
if (fieldHandler != null) {
return (Person) fieldHandler.readObject(this, "owner", owner);
}
return owner;
}
public void setOwner(Person owner) {
if (fieldHandler != null) {
this.owner = fieldHandler.writeObject(this, "owner", this.owner, owner);
return;
}
this.owner = owner;
}
public FieldHandler getFieldHandler() {
return fieldHandler;
}
public void setFieldHandler(FieldHandler fieldHandler) {
this.fieldHandler = fieldHandler;
}
}
我錯過了什么? 也許我對hibernate的生命周期知之甚少? 我很高興調查,但任何人都可以給我一些指示。
提前致謝。
編輯
我推動了很多變化,所以我的很多實體都實現了FieldHandled但后來發現我的一些測試失敗了。 我抽出了SQL並得到了一些奇怪的東西,如果這個接口是用這些方法集實現的,那么SQL會以不同的順序發生。
public FieldHandler getFieldHandler() {
return fieldHandler;
}
public void setFieldHandler(FieldHandler fieldHandler) {
this.fieldHandler = fieldHandler;
}
這導致測試失敗,因為當我斷言時,事情並沒有完全處於正確的狀態。 這增加了我對這個FieldHandler變量的誤解。
以下代碼告訴Hibernate使用攔截處理程序而不是代理。
@LazyToOne(LazyToOneOption.NO_PROXY)
在請求引用時返回加載的實際對象(此選項必須使用字節碼增強,如果未增強類,則返回PROXY)
可以看出,在使用之前需要檢測字節碼。 在''字節碼被檢測'后,'持久類被增強'。
我們的想法是欺騙Hibernate我們想要使用的實體類已經被檢測過了
編譯代碼后調用Instrumentation任務。 檢測實體擴展了FieldHandled
。 FieldHandled
是一個'引入增強類的接口'
Hibernate在運行時驗證實體,並得出結論,類已被增強,這就是為什么它使用真實對象而不是代理, 並且不像通常那樣加載相關的實體對象 。
編輯:
讓我們來看看引擎蓋:
AnnotationBinder處理 NO_PROXY
選項
if ( lazy != null ) { toOne.setLazy( !( lazy.value() == LazyToOneOption.FALSE ) ); toOne.setUnwrapProxy( ( lazy.value() == LazyToOneOption.NO_PROXY ) ); }
無論org.hibernate.mapping.ManyToOne
和org.hibernate.mapping.OneToOne
是子類org.hibernate.mapping.ToOne
。 ToOne#isUnwrapProxy()
僅用於#getType
:
getMappings()。getTypeResolver()。getTypeFactory()。oneToOne(
ManyToOneType
和OneToOneType
都是EntityType
子類,只有'EntityType#unwrapProxy'的使用在EntityType#resolveIdentifier(Serializable, SessionImplementor)
boolean isProxyUnwrapEnabled = unwrapProxy && session.getFactory() .getEntityPersister( getAssociatedEntityName() ) .isInstrumented();
這是暫定的調用層次結構: AbstractEntityPersister#isInstrumented()
- > EntityMetamodel#isInstrumented()
- > EntityInstrumentationMetadata#isInstrumented()
- >等等,最后是BytecodeProviderImpl.EntityInstrumentationMetadataImpl.EntityInstrumentationMetadataImpl()
this.isInstrumented = FieldHandled.class.isAssignableFrom( entityClass );
這就是為什么需要檢測代碼(例如使用InstrumentTask
)或實現FieldHandled
。
為了簡而言之,您可以查看EntityType#resolveIdentifier(Serializable, SessionImplementor)
。 這就是為什么第二個對象即使可以為空也不會被加載的原因。
FieldHandled
接口已被Hibernate 5中的PersistentAttributeInterceptable
接口替換。您可以通過實現此新接口來實現相同的結果:
@Entity
public class Animal implements PersistentAttributeInterceptable {
private Person owner;
private PersistentAttributeInterceptor interceptor;
@OneToOne(fetch = FetchType.LAZY, optional = true, mappedBy = "animal")
@LazyToOne(LazyToOneOption.NO_PROXY)
public Person getOwner() {
if (interceptor != null) {
return (Person) interceptor.readObject(this, "owner", owner);
}
return owner;
}
public void setOwner(Person owner) {
if (interceptor != null) {
this.owner = interceptor.writeObject(this, "owner", this.owner, owner);
return;
}
this.owner = owner;
}
@Override
public PersistentAttributeInterceptor $$_hibernate_getInterceptor() {
return interceptor;
}
@Override
public void $$_hibernate_setInterceptor(PersistentAttributeInterceptor interceptor) {
this.interceptor = interceptor;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.