hibernate - Hibernate Envers 'forEntitiesAtRevision' 生成冗余子查询
问题描述
我正在使用 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 使用通过的修订版作为完全匹配的任何建议,我将不胜感激。
解决方案
我找到了解决我的问题的方法。
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 ?
即使在一张大桌子上也表现得很好。
PSAuditQuery
构造函数其实相当丰富强大!以所需的方式修改查询很容易。谢谢。
推荐阅读
- r - 执行独立样本 t 检验
- jolt - JOLT - 组合数组并添加父键的属性
- ssh - Ansible 无法访问本地主机
- javascript - await 仅在异步函数和模块的顶层主体中有效
- oracle-nosql - 如何查看 Oracle NoSql 数据库中的执行计划?
- windows - 为什么在 Windows 10 上使用 docker 时请求需要这么长时间?
- r - 内联 r 代码块 r studio 可视化编辑器
- amazon-web-services - 从 aws 管理控制台创建应用程序负载均衡器和通过 aws 提供的入口控制器创建有什么区别
- python - 它是如何内部安排到一维的
- c# - 创建一个水印应用程序以覆盖桌面上的所有屏幕