[英]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.