Hibernate Envers with QueryDSL Update

Hibernate Envers with QueryDSL Update

Hibernate、Hibernate Envers 和 QueryDSL 已配置并在 Spring 启动 1.4.1.RELEASE 中正常工作 1.4.1.RELEASE

问题是当使用 UpdateClause<JPAUpdateClause> updateQueryBuilder = queryFactory.update(collectionTransaction); 构建更新查询并执行该更新查询时,Hibernate Envers 不会提取和审核这些更改。

以下是实现 QueryDSL

的 Spring Data JPA 存储库
public class CollectionTransactionRepositoryImpl extends QueryDslRepositorySupport implements CollectionTransactionRepositoryCustom {
    @Autowired
    private JPAQueryFactory queryFactory;

    public CollectionTransactionRepositoryImpl() {
        super(CollectionTransaction.class);
    }

    @Override
    public Collection<CollectionTransaction> updateCollectionTransaction(UpdateCollectionTransaction updateCollectionTransaction) {
        QCollectionTransaction collectionTransaction = QCollectionTransaction.collectionTransaction;
        UpdateClause<JPAUpdateClause> updateQueryBuilder = queryFactory.update(collectionTransaction);
        .....//Code omitted for brevity
        long updated = updateQueryBuilder.execute();
        //.....
        return ...
    }
}

在这种情况下,Hibernate Envers 是否可以获取更改?

这是 JIRA HHH-10318 中概述的已知问题。

Envers 基于 Hibernate 的事件子系统工作,Hibernate 有效地通知各种回调实体的状态已以某种方式修改,并提供先前和新的实体状态。这种状态正是 Envers 用来确定更改内容和插入审计更改行的状态。

让我们举一个简单的例子:

UPDATE MyEntity e SET e.status = :status

Hibernate 将执行以下任务:

  1. 刷新持久性上下文的任何修改。
  2. 使 MyEntity.
  3. 的所有缓存实例失效
  4. 执行批量更新操作。

在任何这些步骤中,Hibernate 都没有加载任何现有状态。它只是保证在批量更新之前刷新当前更改,并且由于批量更新,任何后续操作将从数据存储而不是缓存中获取。

因此,从 Envers 的角度来看,它没有回调,因此不知道发生了任何操作,因为 Hibernate ORM 无法为此类操作提供任何实体状态,它根本不存在。

这里的大问题是如何(如果可能的话)为这样的操作建模和处理变更单元。

这很困难,因为 Envers 实际上需要某种类型的 PreBulkOpEvent 以便它可以缓存它需要的即将更改的内容和 PostBulkOpEvent 来要求和合并两个结果以生成更改日志条目。对这种概念的关注实际上集中在如何有效地做到这一点以避免

  1. 运行 由于大量结果集操作导致内存不足。
  2. 从数据存储加载状态以进行大型结果集操作的执行时间很长。

无论如何,欢迎您阅读 JIRA 并提供任何反馈或想法。但目前,它只是超出了我们目前所能捕捉到的范围。