web-dev-qa-db-ja.com

Java-JPA-@Versionアノテーション

@VersionアノテーションはJPAでどのように機能しますか?

次のような抜粋があるさまざまな答えを見つけました。

JPAは、エンティティのバージョンフィールドを使用して、同じデータストアレコードの同時変更を検出します。 JPAランタイムは、同じレコードを同時に変更しようとする試みを検出すると、最後にコミットしようとしているトランザクションに例外をスローします。

しかし、それがどのように機能するのかはまだわかりません。


また、次の行から:

バージョンフィールドは不変と見なす必要があります。フィールド値を変更すると、未定義の結果が生じます。

バージョンフィールドをfinalとして宣言する必要があるということですか?

107
Yatendra Goel

しかし、それでもそれがどのように機能するのか分かりませんか?

エンティティMyEntityに注釈付きのversionプロパティがあるとします。

@Entity
public class MyEntity implements Serializable {    

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @Version
    private Long version;

    //...
}

更新時に、@Versionアノテーションが付けられたフィールドがインクリメントされ、次のようなWHERE句に追加されます。

UPDATE MYENTITY SET ..., VERSION = VERSION + 1 WHERE ((ID = ?) AND (VERSION = ?))

WHERE句がレコードと一致しない場合(同じエンティティが別のスレッドによって既に更新されているため)、永続化プロバイダーはOptimisticLockExceptionをスローします。

バージョンフィールドを最終として宣言する必要があるということですか?

いいえ、セッターを呼び出す必要はないので、セッターを保護することを検討できます。

177
Pascal Thivent

@Pascalの答えは完全に有効ですが、私の経験から、以下のコードは楽観的なロックを達成するのに役立ちます。

@Entity
public class MyEntity implements Serializable {    
    // ...

    @Version
    @Column(name = "optlock", columnDefinition = "integer DEFAULT 0", nullable = false)
    private long version = 0L;

    // ...
}

どうして?なぜなら:

  1. 楽観的ロック動作しません@Versionアノテーションが付けられたフィールドが誤ってnullに設定されている場合。
  2. この特別なフィールドは必ずしも誤解を避けるためにビジネスバージョンではないため、このようなフィールドにはoptlockではなくversionのような名前を付けることをお勧めします。

JPAベンダーは作成時に0フィールドに@versionフィールドを適用するため、アプリケーションがonly JPAを使用してデータベースにデータを挿入する場合、最初のポイントは重要ではありません。ただし、ほとんどの場合、プレーンSQLステートメントも使用されます(少なくともユニット/統合テスト中)。

26
G. Demecki

データベース内のエンティティが更新されるたびに、バージョンフィールドが1ずつ増加します。データベース内のエンティティを更新するすべての操作では、クエリにWHERE version = VERSION_THAT_WAS_LOADED_FROM_DATABASEが追加されます。

操作の影響を受けた行をチェックする際に、jpaフレームワークは、バージョン番号がロードと持続の間で増加したときにクエリがデータベースでエンティティを見つけられないため、エンティティのロードと持続の間に同時変更がないことを確認できます。

9
stefanglase

一度に1つの更新のみを保証するために使用されるバージョン。 JPAプロバイダーはバージョンをチェックします。予想されるバージョンが既に増加している場合、他の誰かが既にエンティティを更新しているため、例外がスローされます。

したがって、エンティティ値の更新はより安全で、より楽観的です。

値が頻繁に変更される場合は、バージョンフィールドを使用しないことを検討してください。たとえば、「カウンターフィールドを持つエンティティは、Webページにアクセスするたびに増加します」

2
uudashr

もう少し情報を追加するだけです。

JPAは内部でバージョンを管理しますが、JPAUpdateClauseを介してレコードを更新するときはバージョンを管理しません。そのような場合、クエリにバージョンの増分を手動で追加する必要があります。

ペドロ

0
Pedro Borges