2016-05-20 1 views
3

私はこのテーマについて既にいくつか質問があることを知っていますが、これは異なると思います。JPAバージョンエンティティマージ

@Entity 
public class foo{ 
    @Id 
    @GeneratedValue 
    private long id; 

    @Version 
    private long version; 

    private String description; 
    ... 
} 

彼らは、私はいくつかのオブジェクトを作成して)(JPAを追加使用してDBにそれらを持続:

のは、私はこのクラスを持っているとしましょう。

その後、JPA all()を使用してリポジトリからすべてを取得します。 そのリストから1つのオブジェクトを選択して説明を変更します。

次に、JPA merge()を使用してリポジトリ内のオブジェクトを更新したい(コードを参照)。

ここで問題となるのは、説明を変更しようとすると初めて問題になります(バージョン値は2になります)。 2回目に、オブジェクトが変更されたことを示すOptimisticLockExceptionが発生しました。

私はH2に埋め込みモードのDBを使用しています。

MERGEのCODE:

//First: persist is tried, if the object already exists, an exception is raised and then this code is executed 
try { 
    tx = em.getTransaction(); 
    tx.begin(); 
    entity = em.merge(entity); 
    tx.commit(); 
    } catch (PersistenceException pex) { 
       //Do stuff 
      } 

間違っている可能性がありますか?

ありがとうございます。

EDIT(複数のコード)

// FooのBは「(JPAすべての()、次いで1つの目的は、そのリストから選択される

b.changeDescriptionを使用してDBから全てのオブジェクトを取得することにより得られます。新しい何か!");

//コールupdateメソッド(コードをマージすでに掲載)

+0

があなたの代わりにマージのem.persistを試してみました:

はない場合、それにデフォルト値を追加してみてくださいnullで動作するようになっていませんか?マージメソッドは、更新後にオブジェクトを追跡し続けます。設定がどのようになっているかに応じて、アップデートはすでにDBに送られている可能性があります。 – fhofmann

+0

さらにコードを投稿してください。エンティティを読み込んで変更する方法と、投稿したコードをどのように呼び出すかが関係します。 –

+0

@AlanHay私の状況を表すいくつかのコードで元の投稿を編集しました –

答えて

0

Here are OptimisticLockExceptionががスローされたときに完全に説明ポスト。

また、エンティティの更新時にエンティティをこのメモリ内で検証するのを避けることができますが、EntityManagerで 'detach'メソッドを使用してこのトランザクションの最後でDB側で変更したい場合は、

em.detach(employee); 
1

リスト内の要素を異なるクライアントまたは異なるスレッドから変更しているとします。これがOptimisticLockExceptionの原因です。

1つのスレッドは、それ自身のEntityManagerで、Fooオブジェクトを読み取り、読み取り時に@Versionを取得します。

// select and update AnyEntity from a different EntityManager from a different thread or client 
EntityManager em2 = emf.createEntityManager(); 
EntityTransaction tx2 = em2.getTransaction(); 
tx2.begin(); 
AnyEntity secondEntity = em2.createQuery("select a from AnyEntity a", AnyEntity.class).getSingleResult(); 
secondEntity.setName("name2"); 
em2.merge(secondEntity); 

今、最初のクライアントがデータベースへの変更をコミットする:最初のクライアントがデータベースへの変更をコミットする前に

// select and update AnyEntity 
EntityManager em1 = emf.createEntityManager(); 
EntityTransaction tx1 = em1.getTransaction(); 
tx1.begin(); 
AnyEntity firstEntity = em1.createQuery("select a from AnyEntity a", AnyEntity.class).getSingleResult(); 
firstEntity.setName("name1"); 
em1.merge(firstEntity); 

別のクライアントは、読み取りと同時にFooオブジェクトを更新します。それはその変更を更新するとき

// commit first change while second change still pending 
tx1.commit(); 
em1.close(); 

そして、第2のクライアントがOptimisticLockExceptionを取得します。

// OptimisticLockException thrown here means that a change happened while AnyEntity was still "checked out" 
try { 
    tx2.commit(); 
    em2.close(); 
} catch (RollbackException ex) { 
    Throwable cause = ex.getCause(); 
    if (cause != null && cause instanceof OptimisticLockException) { 
     System.out.println("Someone already changed AnyEntity."); 
    } else { 
     throw ex; 
    } 
} 

参考:Java - JPA - @Version annotation

0

あなたが適切にバージョンフィールドを初期化していますか?

@Version 
private Long version = 0L;