如何强制Hibernate Envers在Spring @Transactional方法中提交修订

use*_*656 6 hibernate spring-transactions hibernate-envers

我正在使用Hibernate Envers来保存对象历史记录.在某些时候,我们想要捕获对象图状态的快照 - 我们可以通过了解相应的Envers修订来实现这一点,然后我们将其存储在审计记录中.

但是我们有一个问题.父对象在我们创建和存储其子审计记录的同一事务中更新 - 完成Envers修订.我们可以得到最新版本:

Number revision = reader.getRevisionNumberForDate(new Date(Long.MAX_VALUE));
Run Code Online (Sandbox Code Playgroud)

或创建新版本:

Number revision = reader.getCurrentRevision(DefaultRevisionEntity.class, true).getId();
Run Code Online (Sandbox Code Playgroud)

并使用其中任何一个,但父母的提交总是发生在那之后.这就是Envers增加修订版的时候.因此,我们实际需要在审计记录中引用的修订始终高于存储的值.在最简单的情况下,我们获取并存储修订版N,但我们需要的父版本存储为N + 1.

可以使用以下方式获取AuditReader读者参考:

JpaTransactionManager transactionManager;  // injected
EntityManagerFactory emf = transactionManager.getEntityManagerFactory();
EntityManager entityManager = emf.createEntityManager();
AuditReader reader = AuditReaderFactory.get(entityManager);
Run Code Online (Sandbox Code Playgroud)

我们正在使用Spring 3 @Transactional注释和Hibernate 4.2.

最小的类图:

Parent.class
    int version           // for hibernate optimistic locking
    String revisionName
    List<AuditChild> audits

AuditChild.class
    int enversRevision    // use to retrieve previous graphs of parent
Run Code Online (Sandbox Code Playgroud)

我尝试了许多方法来强制父项的提交首先发生,其中包括:

  • 使用@Transactional在多个方法中拆分代码(propagation = Propagation.REQUIRES_NEW)
  • 显式调用entityManager.flush();

我尝试的一切都没有效果或引起其他问题.我很高兴听到有效的解决方案.谢谢.

Nar*_*ros 1

一个更简单的选择是使用@Version.

首先,需要配置 Envers 来实际审核乐观锁定字段的值,默认情况下它不会执行此操作。您可以通过设置以下配置来完成此操作:

org.hibernate.envers.do_not_audit_optimistic_locking_field=false
Run Code Online (Sandbox Code Playgroud)

此时,Envers 会将该字段包含在审核历史表中,并将分配的 ORM 版本值复制到审核历史表中。此时,我们有一种独特的方式使用 来连接 ORM 实体行和审计历史记录行@Formula。SQL 公式为:

SELECT e.REV
  FROM YourEntity_AUD e
 WHERE e.originalId.id = id  
   AND e.version = version   
Run Code Online (Sandbox Code Playgroud)

现在,就像向实体添加字段一样简单:

@Formula( /* the SQL from above */)
@NotAudited
private Integer revisionNumber;
Run Code Online (Sandbox Code Playgroud)

HTH。