[英]Hibernate/JPA version concurrency control and DTO/change command patterns
我想使用@Version
進行JPA和Hibernate的樂觀並發控制。
我知道它在兩個並行事務的典型場景中是如何工作的。 我也知道如果我在表單和實體之間有一個1:1映射的CRUD,我可以將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?
}
顯然,如果兩個用戶打開我的GUI,都會進行更改,並一個接一個地執行,在這種情況下,將應用兩個更改,最后一個將“贏”。 我希望這個場景也檢測並發修改(第二個用戶應該得到一個例外)。
我怎樣才能實現它?
如果我正確理解您的問題,您只需要private 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);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.