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 将执行以下任务:
- 刷新持久性上下文的任何修改。
- 使
MyEntity
. 的所有缓存实例失效
- 执行批量更新操作。
在任何这些步骤中,Hibernate 都没有加载任何现有状态。它只是保证在批量更新之前刷新当前更改,并且由于批量更新,任何后续操作将从数据存储而不是缓存中获取。
因此,从 Envers 的角度来看,它没有回调,因此不知道发生了任何操作,因为 Hibernate ORM 无法为此类操作提供任何实体状态,它根本不存在。
这里的大问题是如何(如果可能的话)为这样的操作建模和处理变更单元。
这很困难,因为 Envers 实际上需要某种类型的 PreBulkOpEvent
以便它可以缓存它需要的即将更改的内容和 PostBulkOpEvent
来要求和合并两个结果以生成更改日志条目。对这种概念的关注实际上集中在如何有效地做到这一点以避免
- 运行 由于大量结果集操作导致内存不足。
- 从数据存储加载状态以进行大型结果集操作的执行时间很长。
无论如何,欢迎您阅读 JIRA 并提供任何反馈或想法。但目前,它只是超出了我们目前所能捕捉到的范围。
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 将执行以下任务:
- 刷新持久性上下文的任何修改。
- 使
MyEntity
. 的所有缓存实例失效
- 执行批量更新操作。
在任何这些步骤中,Hibernate 都没有加载任何现有状态。它只是保证在批量更新之前刷新当前更改,并且由于批量更新,任何后续操作将从数据存储而不是缓存中获取。
因此,从 Envers 的角度来看,它没有回调,因此不知道发生了任何操作,因为 Hibernate ORM 无法为此类操作提供任何实体状态,它根本不存在。
这里的大问题是如何(如果可能的话)为这样的操作建模和处理变更单元。
这很困难,因为 Envers 实际上需要某种类型的 PreBulkOpEvent
以便它可以缓存它需要的即将更改的内容和 PostBulkOpEvent
来要求和合并两个结果以生成更改日志条目。对这种概念的关注实际上集中在如何有效地做到这一点以避免
- 运行 由于大量结果集操作导致内存不足。
- 从数据存储加载状态以进行大型结果集操作的执行时间很长。
无论如何,欢迎您阅读 JIRA 并提供任何反馈或想法。但目前,它只是超出了我们目前所能捕捉到的范围。