Hibernate Envers 'forEntitiesAtRevision' 生成冗余子查询

Posted

技术标签:

【中文标题】Hibernate Envers \'forEntitiesAtRevision\' 生成冗余子查询【英文标题】:Hibernate Envers 'forEntitiesAtRevision' generates redundant subqueryHibernate Envers 'forEntitiesAtRevision' 生成冗余子查询 【发布时间】:2020-09-12 14:57:25 【问题描述】:

我正在使用 Hibernate Envers 来审计实体更改。实体和审计表存储在 mysql 数据库中。该解决方案在大多数情况下都可以正常工作,但我发现了一个非常奇怪的问题。

假设我在某个版本中有一个实体状态,我想获取该实体的先前更改。为此,我编写了以下方法:

    public <T> T getLastChange(@Nonnull Object id, @Nonnull Class<T> type, long beforeRev) 
        List<Number> revisions = AuditReaderFactory.get(entityManager).getRevisions(type, id);

        return revisions.stream()
                .map(Number::longValue)
                .filter(rev -> rev < beforeRev)
                .max(Comparator.comparingLong(rev -> rev))
                .map(rev -> AuditReaderFactory.get(entityManager).find(type, type.getName(), id, rev, true))
                .orElse(null);
    

除了find 生成“太安全”的查询之外,它工作正常:

select *
from persons_AUD person_aud0_
where person_aud0_.REV=(select max(person_aud1_.REV) from persons_AUD person_aud1_ where person_aud1_.REV<=462864 and person_aud0_.id=person_aud1_.id)
  and person_aud0_.id=56591;

我已经知道确切的版本了!如何避免这个子查询?我只是想要

select *
from persons_AUD person_aud0_
where person_aud0_.REV=462864
  and person_aud0_.id=56591;

目前,它会导致大型表的性能问题。

对于如何说服 Envers 使用通过的修订版作为完全匹配的任何建议,我将不胜感激。

【问题讨论】:

【参考方案1】:

我找到了解决问题的方法。 AuditReader.find 方法使用 forEntitiesAtRevision 总是产生该子查询。 但是经过一些实验,我注意到另一种方法forRevisionsOfEntity 可以完全按照我的意愿进行操作。 所以我重写了我的查询如下

    public <T> T getPreviousChange(@Nonnull Object id, @Nonnull Class<T> type, int beforeRev) 

        List resultList = getEntityManager().createQuery()
                .forRevisionsOfEntity(type, type.getName(), true, true)
                .add(AuditEntity.id().eq(id))
                .add(AuditEntity.revisionNumber().lt(beforeRev))
                .addOrder(AuditEntity.revisionNumber().desc())
                .setMaxResults(1).getResultList();

        return resultList.isEmpty() ? null : (T) resultList.get(0);
    

现在,我得到的不是 2 个查询,而是一个:

select *
from persons_AUD person_aud0_ 
where person_aud0_.id=? and person_aud0_.REV<? 
order by person_aud0_.REV desc limit ?

即使在大桌子上也能很好地发挥作用。

附: AuditQuery 构造函数其实是相当丰富和强大的! 以所需的方式修改查询很容易。 谢谢。

【讨论】:

以上是关于Hibernate Envers 'forEntitiesAtRevision' 生成冗余子查询的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate Envers

Hibernate Envers @NotAudited 注解

审计没有 Hibernate Envers 的 java 实体

在 Spring Hibernate java 项目中使用“Envers”审计表

审计:对子修改的父实体修订(Javers/Envers/... + Hibernate)

Hibernate Envers 修改了标志行为