11

環境:

私はその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
}

ユーザーを一覧表示する検索ページがあり、ユーザーをクリックして編集します ( userIdURL に入力します)。

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

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 ?

実際、これは私のアプリケーションには当てはまりません...私は、2回目の更新で最初の編集によって更新されたform.getVersion()としても、両方のケースで同じ値を返すことを確認しました。user.version

何か不足していますか?

EntityManagerが生成されます(したがって、マージしようとすると@RequestScoped2 つの異なるにいます...)。EntityManager

私はentityManager.lock(user, LockModeType.OPTIMISTIC_FORCE_INCREMENT)前にやろうとしましたentityManager.merge(...)ここで言ったように)が、助けにはなりませんでした。

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

4

3 に答える 3

7

これについてさらに調査を行いました。

JPA 仕様に従って、バージョン フィールドを変更することは許可されていません。

JPA 2.0 最終仕様、セクション 3.4.2:

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

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

于 2013-06-28T09:51:04.873 に答える
6

実際、私はそれを行う方法を見つけました... しかし、それはあまり効率的ではないと思います (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)、休止状態はversion、独自のコピーされたどこかの値ではなく、設定された値を使用するようになりました...

于 2012-02-15T18:49:43.200 に答える
1

楽観的ロックを手動でトリガーする別の方法を見つけました。キャッシュされた Hibernate のバージョンとエンティティ内のバージョンを比較できます。私は春のデータ JPA を使用して、ff を追加しました。リポジトリへの保存の実装:

EntityEntry entityEntry = entityManager
  .unwrap(SessionImplementor.class)
  .getPersistenceContext()
  .getEntry(entity);

//checked if a cached entry is present
if (entityEntry != null) {

  //Compare cached version with the one in the entity
  if (!Objects.equals(entityEntry.getVersion(), classMetadata.getVersion(entity))) {
    throw new ObjectOptimisticLockingFailureException();
  }
}
于 2018-11-06T04:14:05.363 に答える