合并并获得没有刷新的待更新版本?

ber*_*tie 7 hibernate jpa jpa-2.0

是否可以更改版本化的实体实例,并在不使用flush的情况下获取待增加的版本?因为从我读到的内容来看,即时冲洗并不是一种好的做法,因为它对性能甚至数据损坏都有不良影响?我不确定:D


这是一个简单的代码,输出也是注释:

/*
    Hibernate: select receivingg0_.id as id9_14_, receivingg0_.creationDate as creation2_9_14_, ... too long
    the version before modification : 16
    the version after modification : 16
    after merge the modification, the version is : 16
    Hibernate: update ReceivingGood set creationDate=?, modificationDate=?, usercreate_id=?, usermodify_id=?,  ... too long
    after flushing the modification, the version is finally : 17
*/
public void modifyHeaderAndGetUpdatedVersion() {
    String id = "3b373f6a-9cd1-4c9c-9d46-240de37f6b0f";
    ReceivingGood receivingGood = em.find(ReceivingGood.class, id);
    System.out.println("the version before modification : " + receivingGood.getVersion());

    receivingGood.setTransactionNumber("NUM001xyz");
    System.out.println("the version after modification : " + receivingGood.getVersion());

    receivingGood = em.merge(receivingGood);
    System.out.println("after merge the modification, the version is : " + receivingGood.getVersion());

    em.flush();
    System.out.println("after flushing the modification, the version is finally : " + receivingGood.getVersion());
}
Run Code Online (Sandbox Code Playgroud)

在我的测试中,版本在刷新后增加了.从合并操作返回的实例没有增加的版本.

但在我的情况下,我想以DTO的形式将实体返回到我的webui,并且实体应该在将其转换为DTO并将其返回到要呈现的UI之前具有版本后刷新/提交.用户界面可以拥有最新版本,并将通过此版本进行下一次提交.


有没有办法让我可以在没有刷新的情况下获得最新版本?

谢谢 !


UPDATE


根据我的经验,手动递增可能会有问题,如下面的示例所示.在这个例子中,我们有2次刷新.

第一个是将更改同步到数据库连接,以便来自同一连接的存储过程调用可以查看从entityManager进行的更改.

调用第二次刷新以获得最终版本.我们可以看到它增加了两次.因此,在没有冲洗的情况下从手动增量获取版本在这种情况下无法工作,因为我们必须真正计算正在进行多少次刷新.

/*
Hibernate: select receivingg0_.id as id9_14_, receivingg0_.creationDate as creation2_9_14_, .. too long
the version before modification : 18
the version after modification : 18
after merge the modification, the version is : 18
now flushing the modification, so that the stored procedure call from the same connection can see the changes
Hibernate: update ReceivingGood set creationDate=?, modificationDate=?, usercreate_id=?, .. too long
after flushing the modification, the version is : 19
Hibernate: update ReceivingGood set creationDate=?, modificationDate=?, usercreate_id=?, .. too long
after the second flush, the version got increased again into : 20
*/
public void modifyHeaderAndGetUpdatedVersionWith2Flushes() {
    String id = "3b373f6a-9cd1-4c9c-9d46-240de37f6b0f";
    ReceivingGood receivingGood = em.find(ReceivingGood.class, id);
    System.out.println("the version before modification : " + receivingGood.getVersion());

    //auditEntity(receivingGood, getUser("3978fee3-9690-4377-84bd-9fb05928a6fc"));
    receivingGood.setTransactionNumber("NUM001xyz");
    System.out.println("the version after modification : " + receivingGood.getVersion());

    receivingGood = em.merge(receivingGood);
    System.out.println("after merge the modification, the version is : " + receivingGood.getVersion());
    System.out.println("now flushing the modification, so that the stored procedure call from the same connection can see the changes");
    em.flush();
    System.out.println("after flushing the modification, the version is : " + receivingGood.getVersion());

    receivingGood.setTransactionNumber("NUM001abc");

    em.flush();
    System.out.println("after the second flush, the version got increased again into : " + receivingGood.getVersion());
}
Run Code Online (Sandbox Code Playgroud)

这是否意味着我真的必须依赖最后的flush以获得修改后的实体的最新版本?


更新2


这是一个服务方法的简单示例,它将更新ReceivingGood实体,并应返回具有最新版本的DTO.

public ReceivingGoodDTO update(ReceivingGood entity) {
  // merge it
  entity = entityManager.merge(entity);

  // the version is not incremented yet, so do the flush to increment the version
  entityManager.flush(); // if i dont do this, the dto below will get the unincremented one

  // use a mapper, maybe like dozer, to copy the properties from the entity to the dto object, including the newest version of that entity
  ReceivingGoodDTO dto = mapper.map(entity, dto);

  return dto;
}
Run Code Online (Sandbox Code Playgroud)

这是一个使用该方法的示例:

@Transactional
public ReceivingGoodDTO doSomethingInTheServiceAndReturnDTO() {
  // do xxx ..
  // do yyy ..
  dto = update(entity);
  return dto; // and the transaction commits here, but dto's version isnt increased because it's not a managed entity, just a plain POJO
}
Run Code Online (Sandbox Code Playgroud)

jpk*_*ing 5

我将再次建议阅读有关Hibernate及其工作原理的更多信息,无论是通过其文档还是"Java Persistence with Hibernate".

您在刷新操作中看到了这一点,因为这是数据库更新发生的地方.如果您只是省略flush并提交事务,您将看到相同的行为.这意味着,只要您的工作单元完成,Hibernate就会刷新对数据库的更改.正是在这一步中,Hibernate比较并更新了版本号.如果数据库版本是17并且您正在更新版本16,则Hibernate将抛出一个关于更新陈旧对象的异常.

也就是说,您可以通过在实例中当前具有的值递增1来"预测"下一个版本的内容.但这永远不会是真实的,因为这只会在更新数据库记录之前有效地增加.因此,除非您查询数据库,否则任何并发更改都不会对您的线程可见.

编辑:

您正在看两个增量,因为您正在进行两次刷新."版本"是一种"乐观"锁定的技术,这意味着,您希望在任何工作单元期间只有一个线程会更新记录(在更广泛的意义上,将其视为"用户操作",他列出了记录,选择一个并更新它).它的目的主要是避免Hibernate更新过时的对象,其中两个用户选择相同的记录进行编辑,进行一些并发更改并对其进行更新.其中一个编辑将不得不被拒绝,第一个编辑数据库获胜.当你更新记录两次时(通过调用flush两次),你会看到两个增量.但它真的不是关于刷新,而是关于"数据库中发布的更新".如果您有两个交易,您会看到相同的行为.

也就是说,值得注意的是,这种技术应该由Hibernate管理.你不应该自己增加它.不为这种领域提供制定者通常是一种好习惯.

换句话说:您应该将"版本"视为只读值,并且您无法控制它.因此,在屏幕上为用户显示其值是安全的,但操纵它(或"确定"下一个版本)是不安全的.最多,您可以做出"最佳猜测",预测它将是current_version + 1.