You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate 5.3+调用getHibernateLazyInitializer获取ID报EntityNotFoundException

Hibernate 5.3+ 结合Envers使用时,AuditedReader加载的Proxy调用getIdentifier()抛出EntityNotFoundException问题

问题描述

升级至Hibernate 5.3+版本后,调用由Hibernate Envers的AuditedReader加载的HibernateProxy对象的getHibernateLazyInitializer().getIdentifier()方法时,抛出javax.persistence.EntityNotFoundException异常。数据库中存在对应ID的实体记录,调试时代码可正常返回结果,但正常运行时抛出异常。已尝试升级Hibernate版本未解决,当前环境为JBoss 7.4 EAP补丁11,依赖版本:

  • hibernate-core-5.3.29.Final-redhat-00001
  • hibernate-envers-5.3.28.Final-redhat-00001
  • javax.persistence.api

相关代码示例

@Entity
@Audited
public class Person {
    @Id
    private Long id;
    
    @Column(name="surname")
    private String name;

    @JoinColumn(name="country_id", foreignKey = @javax.persistence.ForeignKey(name="FK_country_id"))
    @ManyToOne(cascade = { CascadeType.REFRESH }, fetch = FetchType.EAGER)
    @Fetch(FetchMode.SELECT)
    private Country country;
}

@Entity
@Audited
public class Country {
    @Id
    public Long id;

    @Column(name="countryName")
    public String countryName;
}

// 从Envers审计表的Person对象中获取Country的ID
private static Object getId(Object personObject, Field field) throws IllegalAccessException {
    Object countryObject = field.get(personObject);
    if (countryObject instanceof HibernateProxy) {
        return ((HibernateProxy)countryObject).getHibernateLazyInitializer().getIdentifier();
    }
    return null;
}

报错堆栈信息

javax.persistence.EntityNotFoundException: Unable to find entity.Country with id 10
    at org.hibernate@5.3.29.Final-redhat-00001//org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$JpaEntityNotFoundDelegate.handleEntityNotFound(EntityManagerFactoryBuilderImpl.java:163)
    at org.hibernate@5.3.29.Final-redhat-00001//org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:291)
    at org.hibernate@5.3.29.Final-redhat-00001//org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:186)
    at org.hibernate@5.3.29.Final-redhat-00001//org.hibernate.proxy.AbstractLazyInitializer.getIdentifier(AbstractLazyInitializer.java:95)

解决方向与方案

1. 统一Hibernate Core与Envers版本

当前依赖中hibernate-core(5.3.29)和hibernate-envers(5.3.28)版本不一致,可能引发内部API兼容性问题。将hibernate-envers升级至与core相同的版本(5.3.29.Final-redhat-00001),再验证问题是否解决。

2. 绕过Proxy直接读取审计表中的关联ID

Envers会在审计表中存储关联实体的外键值(如person_aud表中的country_id字段),无需通过Proxy对象获取ID:

  • 通过反射直接读取Person审计对象中对应外键的字段(而非country关联对象);
  • 使用Envers的查询API(AuditQuery)直接查询审计数据中的关联ID,例如:
    AuditQuery query = reader.createQuery()
        .forEntitiesAtRevision(Person.class, revisionNumber)
        .add(AuditEntity.id().eq(personId));
    Person person = (Person) query.getSingleResult();
    // 直接读取country_id字段,需确保字段可访问
    Field countryIdField = Person.class.getDeclaredField("country_id");
    countryIdField.setAccessible(true);
    Long countryId = (Long) countryIdField.get(person);
    

3. 避免Proxy初始化触发的查询

Hibernate 5.3+中,AbstractLazyInitializer.getIdentifier()会触发Proxy初始化(检查目标实体状态),若此时EntityManager已关闭或上下文异常,会导致查询失败。可通过以下方式规避:

  • 使用内部API读取标识符(不推荐,依赖Hibernate内部实现):通过反射读取AbstractLazyInitializer中的identifier字段,跳过初始化检查:
    if (countryObject instanceof HibernateProxy) {
        LazyInitializer initializer = ((HibernateProxy) countryObject).getHibernateLazyInitializer();
        Field identifierField = AbstractLazyInitializer.class.getDeclaredField("identifier");
        identifierField.setAccessible(true);
        return identifierField.get(initializer);
    }
    
  • 确保操作在EntityManager上下文内:调用getIdentifier()时,确保AuditedReader对应的EntityManager处于打开状态,避免上下文关闭后触发Proxy初始化。

4. 调整Envers关联实体的加载策略

修改实体类的关联配置,避免Envers生成Proxy对象:

  • 将@Fetch(FetchMode.SELECT)改为@Fetch(FetchMode.JOIN),让Envers在加载Person审计数据时直接关联查询Country,避免生成Proxy;
  • 检查Envers配置参数org.hibernate.envers.proxy.enabled,若设置为false可禁用Proxy生成(需验证Hibernate 5.3是否支持该参数)。

内容的提问来源于stack exchange,提问作者Skyverian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 10:37:43