@Version
JPA と Hibernate を使用した楽観的同時実行制御に使用したいと考えています。
2 つの並列トランザクションの典型的なシナリオでそれがどのように機能するかを知っています。version
また、フォームとエンティティ間の 1:1 マッピングを持つ CRUD がある場合、非表示フィールドとして渡して、これを使用してユーザーによる同時変更を防ぐことができることも知っています。
DTO を使用したり、コマンド パターンを変更したりする、より興味深いケースについてはどうでしょうか。@Version
このシナリオでも使用できますか?また、どのように使用できますか?
例を挙げましょう。
@Entity
public class MyEntity {
@Id private int id;
@Version private int version;
private String someField;
private String someOtherField;
// ...
}
ここで、2 人のユーザーがこのために GUI を開き、いくつかの変更を行い、変更を保存するとします (同時にではなく、トランザクションが重複しないようにします)。
エンティティ全体を渡すと、2 番目のトランザクションは失敗します。
@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?
}
明らかに、2 人のユーザーが私の GUI を開いた場合、両方が変更を行い、それを次々に実行します。この場合、両方の変更が適用され、最後の変更が「勝ち」ます。このシナリオで同時変更も検出したいと思います (2 番目のユーザーは例外を受け取る必要があります)。
どうすれば達成できますか?