java - Hibernate 实体代理初始化

标签 java hibernate jpa orm proxy

我在使用未初始化的 Hibernate 实体时遇到问题。
似乎它仍在返回一个未初始化的代理...

如果我查看我的调试信息,我希望我的实体已被初始化。
但它看起来像下面这样:

entity = {SomeEntity_$$_jvst47c_1e@9192}"SomeEntityImpl@1f3d4adb[id=1,version=0]"
    handler = {org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer@9196}
        interfaces = {java.lang.Class[2]@9197}
        constructed = true
        persistentClass = {java.lang.Class@3605}"class SomeEntityImpl"
        getIdentifierMethod = null
        setIdentifierMethod = null
        overridesEquals = true
        componentIdType = null
        replacement = null
        entityName = {java.lang.String@9198}"SomeEntityImpl"
        id = {java.lang.Long@9199}"1"
        target = {SomeEntityImpl@9200}"SomeEntityImpl@1f3d4adb[guid=<null>,id=1,version=0]"
        initialized = true
        readOnly = true
        unwrap = false
        session = {org.hibernate.internal.SessionImpl@6878}"SessionImpl(PersistenceContext[entityKeys=[EntityKey[EntityReferenceImpl#2], EntityKey[SomeEntityImpl#1], EntityKey[...
        readOnlyBeforeAttachedToSession = null
        sessionFactoryUuid = null
        allowLoadOutsideTransaction = false

请注意,我的 Hibernate POJO 仍然只包含一个处理程序,即使在进行了显式初始化之后...
在我的调试 View 中,当我展开 target 节点时,我可以看到“真实的”属性值(上面未显示)。

我在做什么:

EntityReferenceImpl entityReference = findEntityReference(session);
SomeEntity entity = null;
if (entityReference != null) {
    // initialize association using a left outer join
    HibernateUtil.initialize(entityReference.getSomeEntity());
    entity = entityReference.getSomeEntity();
}
return entity;

注意 HibernateUtil.initialize 调用!

SomeEntity 映射:

public class SomeEntityImpl extends AbstractEntity implements SomeEntity {
    @OneToMany(mappedBy = "someEntity", fetch = FetchType.EAGER, targetEntity = EntityReferenceImpl.class, orphanRemoval = true)
    @Cascade(CascadeType.ALL)
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    private Set<EntityReference> entityReferences = new HashSet<>();

    @Target(EntityName.class)
    @Embedded
    private Name name;

    @Target(EntityAddress.class)
    @Embedded
    private Address address;

    ...

}

EntityReferenceImpl 映射:

public class EntityReferenceImpl extends AbstractEntity implements EntityReference {

@ManyToOne(optional = true, fetch = FetchType.LAZY, targetEntity = SomeEntityImpl.class)
@JoinColumn(name = "entity_id")
private SomeEntity someEntity;

...

}

那么副作用是什么:当 POJO 稍后带有更新的属性时,我仍然具有相同的结构(如上所述)并且我可以在 target 节点下看到更新的属性。
但是当我尝试使用 session.merge()session.update()session.saveOrUpdate() 更新实体时, Hibernate 不检测“脏”属性,也不调用对数据库的更新查询。


有没有人对这种奇怪的行为有一些线索?我已经尽我所能但没有任何结果。
非常欢迎所有帮助!

最佳答案

调试窗口中的实体看起来已正确初始化

当你有一些实体可能被 hibernate 代理时,这个实体存储在内部代理对象即使在正确初始化之后。初始化后代理对象本身不会消失...

public class EntityReferenceImpl extends AbstractEntity implements EntityReference {

@ManyToOne(fetch = FetchType.LAZY, ...)
private SomeEntity someEntity;
...

在您的示例中,您有 EntityReferenceImpl具有 @ManyToOne(LAZY) 的实体至 SomeEntity实体。

当 hibernate 加载时 EntityReferenceImpl它填充了 resultSet 值中的所有字段,但 someEntity字段设置为代理对象。

这个代理对象看起来像这样:

class SomeEntity_$$_javassist_3 extends SomeEntity implements HibernateProxy {
  + firstname = NULL;
  + lastname = NULL;
  + age = 0;
  + handler; //of type: JavassistLazyInitializer

  getFirstname() {
    handler.invoke(..., Method thisMethod, Method proceed, args);
  }
  getLastName() {...}
}

你的 SomeEntity类有(例如)方法 getFirstName()等等,但是 javassist 生成的类 只是扩展了你的 SomeEntity并且几乎没有新的字节码生成方法,如 c7getFirstName()等等

最重要 - 代理类有新字段:handler类型 JavassistLazyInitializer .

让我们看看如何 JavassistLazyInitializer看起来像:

JavassistLazyInitializer {
  + target; //holds SomeEntity object
  invoke(..., Method thisMethod, Method proceed, args) {
    if (target == null) {
      target = initialize(); // calls sessionImpl.immediateLoad
    }
    return thisMethod.invoke( target, args );
  }
}

因此,当您查看代理对象时 - 它您的字段,例如 firstname , lastname等等 当您初始化此代理时,SomeEntity加载到到目标字段中。你的firstname , lastname代理对象上的字段和以前一样为空 - 代理不使用它们,但真实数据在SomeEntitytarget持有的对象字段。

在hibernate中代理是这样实现的。

您可能会问 - 为什么这样的解决方案?这样的设计来自多态问题。如果SomeEntity将是具有 2 个子类的抽象父类 EntityAEntityB hibernate 没有问题 - someEntity 字段包含代理(生成的)类扩展 SomeEntity但有混凝土EntityAEntityB里面target字段。

然而,这种解决方案和多态性存在一些缺陷。你的someEntity字段将为 instance of SomeEntity从不 instance of EntityA也不instance of EntityB .

关于java - Hibernate 实体代理初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26165188/

相关文章:

java - Monty Hall 让我们做一笔交易 用 java 模拟(10000 次迭代)

java - 在 Java 中查找大数的阶乘

java - Hibernate 从表中获取具有最大字段值的单行

java - @Embedded beans作为最终属性?

JAVA使用自定义keycloak的User Storage Provider登录Mysql

java - 为什么无法使用 JPA TopLink 注释连接第三个表?

Java - java.net.NoRouteToHostException : No route to host: connect

java - ArrayList每次显示的执行时间不同,为什么?

java - hibernate单独的jar lib

java - hibernate/Java : retrieving primary key always returns zero