Java Hibernate/JPA版本并发控制和DTO/change命令模式

Java Hibernate/JPA版本并发控制和DTO/change命令模式,java,hibernate,jpa,concurrency,optimistic-concurrency,Java,Hibernate,Jpa,Concurrency,Optimistic Concurrency,我想使用@Version对JPA和Hibernate进行乐观并发控制 我知道它在两个并行事务的典型场景中是如何工作的。我还知道,如果我有一个CRUD,在表单和实体之间有1:1的映射,我可以将version作为一个隐藏字段传递,并使用它来防止用户并发修改 更有趣的情况是使用DTO还是更改命令模式?在这种情况下是否也可以使用@Version,以及如何使用 让我给你举个例子 @Entity public class MyEntity { @Id private int id; @Ver

我想使用
@Version
对JPA和Hibernate进行乐观并发控制

我知道它在两个并行事务的典型场景中是如何工作的。我还知道,如果我有一个CRUD,在表单和实体之间有1:1的映射,我可以将
version
作为一个隐藏字段传递,并使用它来防止用户并发修改

更有趣的情况是使用DTO还是更改命令模式?在这种情况下是否也可以使用
@Version
,以及如何使用

让我给你举个例子

@Entity
public class MyEntity {
    @Id private int id;
    @Version private int version;
    private String someField;
    private String someOtherField;
    // ...
}
现在让我们假设两个用户为此打开GUI,进行一些修改并保存更改(不要同时进行,这样事务就不会重叠)

如果我传递整个实体,第二个事务将失败:

@Transactional
public void updateMyEntity(MyEntity newState) {
    entityManager.merge(newState);
}
这很好,但我不喜欢到处传递实体,有时会使用DTO、更改命令等

为简单起见,change命令是一个映射,最终用于某些服务上的调用,如下所示:

@Transactional
public void updateMyEntity(int entityId, int version, Map<String, Object> changes) {
    MyEntity instance = loadEntity(entityId);
    for(String field : changes.keySey()) {
        setWithReflection(instance, field, changes.get(field));
    }
    // version is unused - can I use it somehow?
}
@Transactional
public void updateMyEntity(int-entityId、int-version、映射更改){
MyEntity实例=loadEntity(entityId);
for(字符串字段:changes.keySey()){
setWithReflection(实例、字段、changes.get(字段));
}
//版本未使用-我可以以某种方式使用它吗?
}
显然,如果两个用户打开我的GUI,他们都进行了更改,并一个接一个地执行,在这种情况下,两个更改都将应用,最后一个将“获胜”。我希望这个场景也能检测到并发修改(第二个用户应该会得到一个异常)


如何实现它?

如果我正确理解您的问题,您只需要为
私有int version
字段设置一个setter,当您更新实体时,您可以在实体中设置它。当然,DTO必须始终传输版本数据。最终,您还将执行以下操作:

MyEntity instance = loadEntity(entityId);
entityManager.detach(instance);
for(String field : changes.keySey()) {
    setWithReflection(instance, field, changes.get(field));
}
//set also the version field, if the loop above does not set it
entityManager.merge(instance);