当前位置: 首页 > 知识库问答 >
问题:

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

谯嘉木
2023-03-14

我正在使用Hibernate Envers来持久化对象历史。在某些情况下,我们希望捕获对象图状态的快照—我们可以通过了解相应的Envers修订版来实现这一点,然后将其存储在审计记录中。

然而,我们有一个问题。父对象在我们创建和存储其子审核记录的同一事务中更新,并使用Envers revision完成。我们可以获得最新版本:

Number revision = reader.getRevisionNumberForDate(new Date(Long.MAX_VALUE));

或创建新修订:

Number revision = reader.getCurrentRevision(DefaultRevisionEntity.class, true).getId();

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

AuditReader读者参考可以通过以下方式获得:

JpaTransactionManager transactionManager;  // injected
EntityManagerFactory emf = transactionManager.getEntityManagerFactory();
EntityManager entityManager = emf.createEntityManager();
AuditReader reader = AuditReaderFactory.get(entityManager);

我们正在使用Spring3@Transactional注释和Hibernate4.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

我已经尝试了许多方法来强制首先发生家长的promise,其中包括:

  • 使用@Transactional(传播=传播)在多个方法之间html" target="_blank">拆分代码。REQUIRES_NEW)
  • 实体的明确调用anager.flush();

我尝试过的一切要么没有效果,要么导致了其他问题。我很高兴听到对其他人有用的解决方案。谢谢

共有1个答案

楚昊明
2023-03-14

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

首先,Envers需要配置为实际审计乐观锁定字段的值,默认情况下它不会这样做。为此,您可以设置以下配置:

org.hibernate.envers.do_not_audit_optimistic_locking_field=false

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

SELECT e.REV
  FROM YourEntity_AUD e
 WHERE e.originalId.id = id  
   AND e.version = version   

现在,只需将字段添加到实体中即可:

@Formula( /* the SQL from above */)
@NotAudited
private Integer revisionNumber;

HTH.

 类似资料:
  • 问题内容: 我正在使用Spring / Spring-data-JPA,发现自己需要在单元测试中手动强制提交。我的用例是我正在做一个多线程测试,其中我必须使用在生成线程之前保留的数据。 不幸的是,鉴于测试正在事务中运行,即使不能使它也不能被衍生线程访问。 我尝试使用实体管理器来执行操作,但是在执行此操作时收到错误消息: 有什么方法可以提交事务并继续进行吗?我一直找不到任何允许我调用的方法。 问题答

  • 我正在使用Spring/Spring数据JPA,发现自己需要在单元测试中手动强制提交。我的用例是,我正在做一个多线程测试,在这个测试中,我必须使用在生成线程之前持久化的数据。 不幸的是,鉴于测试在事务中运行,即使是也无法让生成的线程访问它。 我曾尝试使用实体管理器来执行以下操作,但执行此操作时会收到错误消息: 有什么方法可以提交事务并继续它吗?我找不到任何允许调用提交()的方法。

  • 问题内容: 在一个岛中,我有2个@Transactional方法。 如果我不提供任何明确的属性, 那会发生什么,如果 我在另一种体内运行一种方法? 两种方法都可以在同一交易中运行吗? 问题答案: 春季AOP中的代理 使用事务性时,您要处理类的代理,因此在这种情况下: 您从外部调用代理,但是第二个方法调用是从代理对象内部进行的,因此没有事务支持。所以自然地,它们运行在同一事务中,无论第二种方法中@T

  • 由于此错误,以前的提交被回滚,但它不应该回滚。 不确定导致此回滚的原因。

  • 问题内容: 我必须创建许多非常相似的类,它们之间只有一种方法不同。因此,我认为创建抽象类将是实现此目标的好方法。但是我要覆盖的方法(例如,方法foo())没有默认行为。我不想保留任何默认实现,而是强制所有扩展类都实现此方法。我该怎么做呢? 问题答案: 您需要在基类上使用 抽象 方法: 这样,您无需指定默认行为 , 而是可以强制从继承的非抽象类指定的实现。

  • 我正在尝试使用H2数据库使用maven来构建代码来学习Spring, Hibernate。目前我有一些问题,如何正确使用@Transactional注释来自动启动事务并在例如entityManager.persist成功或回滚时提交事务。 我的测试项目非常简单。POJO类是Person,包含名字、姓氏和电子邮件地址。有一个服务类PersonSerice,它是一个接口,提供CRUD函数来添加、更改、