我今天遇到问题,在使用按映射的集合时,延迟加载无法正常工作。我发现这篇出色的文章似乎可以解决问题
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)
从javadoc:
返回请求引用时加载的真实对象(此选项必须增强字节码,如果未增强该类,则退回到PROXY)
可以看出,在使用字节码之前需要对其进行检测。检测“字节码”后,“持久类得到增强”。
这个想法是要愚弄Hibernate,我们要使用的实体类已经被检测了
编译代码后将调用检测任务。工具实体扩展FieldHandled。FieldHandled是“引入增强类的接口”
FieldHandled
Hibernate在运行时验证实体,并得出结论,类得到了增强,这就是为什么它使用真实对象而不是代理并且不像往常那样加载相关实体对象的原因。
编辑:
让我们来看看幕后花絮:
AnnotationBinder句柄 NO_PROXY选项
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:
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)
ManyToOneType
OneToOneType
EntityType
EntityType#resolveIdentifier(Serializable, SessionImplementor)
boolean isProxyUnwrapEnabled = unwrapProxy && session.getFactory() .getEntityPersister( getAssociatedEntityName() ) .isInstrumented();
这是暂定的呼叫层次结构:AbstractEntityPersister#isInstrumented()-> EntityMetamodel#isInstrumented()-> EntityInstrumentationMetadata#isInstrumented()->等,最后BytecodeProviderImpl.EntityInstrumentationMetadataImpl.EntityInstrumentationMetadataImpl()
AbstractEntityPersister#isInstrumented()
EntityMetamodel#isInstrumented()
EntityInstrumentationMetadata#isInstrumented()
BytecodeProviderImpl.EntityInstrumentationMetadataImpl.EntityInstrumentationMetadataImpl()
this.isInstrumented = FieldHandled.class.isAssignableFrom( entityClass );
这就是为什么需要检测代码(例如使用InstrumentTask)或实现的原因FieldHandled。
InstrumentTask
为了使长话短说你可以看一看EntityType#resolveIdentifier(Serializable, SessionImplementor)。这就是为什么即使第二个对象为空也不会加载的原因。