Hibernate 4で@Versionフィールドを手動で設定するには?

環境:

私はその User エンティティを持っています:

@Entity
public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer userId;

    @Version
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "VERSION", length = 19)
    private Date version;

    @Column(nullable = false, length = 20)
    private String login;

   //Getters and Setters
}

私はユーザーをリストする検索ページを持っています。ユーザーをクリックして編集します(URLに userId を付ける)。

編集フォームでは、サーバー上にそのエンティティのフィールドを保存します。ユーザーを保存するときは、次の操作を行います。

User user = entityManager.find(User.class, userId)
user.setLogin(form.getLogin());
user.setVersion(form.getVersion());
user.setUserId(form.getUserId());
entityManager.merge(user);

質問:

ですから、もしHibernateで楽観的なロックを正しく理解していたら、ブラウザで2つのタブを開いて同じユーザを編集し、最初のタブでログインを 更新し、 2番目のタブにログインすると、私は OptimisticLockException をしてはいけませんか?

実際には、これは私のアプリケーションではそうではありません...私は検証しましたが、 form.getVersion()は、2番目の更新でも user .version は最初の編集で更新されました。

何か不足していますか?

EntityManager は、 @RequestScoped で生成されます(マージしようとすると、2つの異なる EntityManager です)。

entityManager.merge(...) entityManager.lock(user、LockModeType.OPTIMISTIC_FORCE_INCREMENT)それは助けにはなりませんでした。

Seam 3をJBoss 7.0.2.Final(これはHibernate 4を使用しています)で使用しています。

8
entityManagerがフラッシュされた(またはトランザクションがコミットされた)のですか?生成されたSQL更新クエリは何ですか?
追加された 著者 JB Nizet,
はい、 Hibernate SQLのダンプのアクティブ化 User に設定した version に対応していないSQLのアップデートとJDBCの version WHERE id =? FlushInterceptor は、 update 関数の存在後に呼び出され、 entityManager.flush( )
追加された 著者 Anthony O.,

2 答え

私はちょうどこれについてさらに研究をしました。

JPA仕様に従ってバージョンフィールドを変更できません

JPA 2.0最終仕様、3.4.2項:

エンティティは、バージョンフィールドまたはプロパティの状態にアクセスしたり、アプリケーションがバージョンにアクセスするためのメソッドをエクスポートしますが、バージョン値を変更してはいけません。セクション4.10に記載されている例外を除き、オブジェクトのバージョン属性の値を設定または更新できるのは、永続プロバイダのみです。

注:セクション4.10は、バージョン属性を無視するバッチ更新を参照しています。

5
追加された

実際に私はそれを行う方法を見つけました...しかし、それは実際に効率的ではないと思います(SELECTリクエストがもう1つあるためです)。

User user = entityManager.find(User.class, userId)
user.setLogin(form.getLogin());
user.setVersion(form.getVersion());
user.setUserId(form.getUserId());

entityManager.detach(user);
entityManager.merge(user);

entityManager.detach(user) を使用すると、hibernateは、独自のコピーされたどこかの値の代わりに、設定された version

4
追加された