8

我今天在使用映射集合时遇到延迟加载无法正常工作的问题。我发现这篇优秀的文章似乎可以解决问题

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 变量的误解。

4

2 回答 2

14

以下代码告诉 Hibernate 使用拦截处理程序而不是代理。

@LazyToOne(LazyToOneOption.NO_PROXY)

来自 javadoc:

返回请求引用时加载的真实对象(此选项强制执行字节码增强,如果未增强类则回退到 PROXY)

可以看出,在使用字节码之前需要对其进行检测。在“检测字节码”之后“增强了持久类”。

这个想法是欺骗 Hibernate,我们想要使用的实体类已经被检测了

代码编译后调用检测任务。仪表化实体扩展FieldHandled. FieldHandled是“引入增强类的接口”

Hibernate 在运行时验证实体并得出一个结论,即类得到了增强,这就是它使用真实对象而不是代理并且没有像往常那样加载相关实体对象的原因

编辑:

让我们来看看引擎盖下:

  1. AnnotationBinder 处理 NO_PROXY选项

    if ( lazy != null ) {
        toOne.setLazy( !( lazy.value() == LazyToOneOption.FALSE ) );
        toOne.setUnwrapProxy( ( lazy.value() == LazyToOneOption.NO_PROXY ) );
    }
    
  2. org.hibernate.mapping.ManyToOne和都是org.hibernate.mapping.OneToOne的子类org.hibernate.mapping.ToOneToOne#isUnwrapProxy()唯一的用法是#getType

    getMappings().getTypeResolver().getTypeFactory().oneToOne(

  3. ManyToOneType和都是'EntityType#unwrapProxy' 的OneToOneType子类,只有在EntityTypeEntityType#resolveIdentifier(Serializable, SessionImplementor)

    boolean isProxyUnwrapEnabled = unwrapProxy &&
            session.getFactory()
                    .getEntityPersister( getAssociatedEntityName() )
                    .isInstrumented();
    
  4. 这是暂定调用层次结构:AbstractEntityPersister#isInstrumented()-> EntityMetamodel#isInstrumented()-> EntityInstrumentationMetadata#isInstrumented()-> 等,最后BytecodeProviderImpl.EntityInstrumentationMetadataImpl.EntityInstrumentationMetadataImpl()

     this.isInstrumented = FieldHandled.class.isAssignableFrom( entityClass );
    

这就是为什么需要检测代码(例如 with InstrumentTask)或实现FieldHandled


为了长话短说,你可以看看EntityType#resolveIdentifier(Serializable, SessionImplementor)这就是为什么第二个对象即使可以为空也不会加载的原因。

于 2013-06-20T00:02:33.267 回答
12

FieldHandled接口已替换为PersistentAttributeInterceptableHibernate 5 中的接口。您可以通过实现这个新接口来实现相同的结果:

@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;
    }
}
于 2016-05-06T13:12:25.050 回答