2011-01-06 14 views
0

Glassfish ContainerでJPAを使用しています。私は次のモデル(完全ではない)を持っていますJPAコレクションでエンティティを更新するベストプラクティス

@Entity 
public class Node { 
    @Id 
    private String serial; 
    @Version 
    @Column(updatable=false) 
    protected Integer version; 
    private String name; 
    @ManyToMany(cascade = {CascadeType.PERSIST,CascadeType.MERGE}) 
    private Set<LUN> luns = new HashSet<LUN>(); 

@Entity 
public class LUN { 
    @Id 
    private String wwid; 
    @Version 
    @Column(updatable=false) 
    protected Integer version; 
    private String vendor; 
    private String model; 
    private Long capacity; 
    @ManyToMany(mappedBy = "luns") 
    private Set<Node> nodes = new HashSet<Node>(); 

この情報は毎日更新されます。今私の質問は、これを行うベストプラクティスは何ですか。

私のアプローチは、毎日新しいものをクライアント上で(LUNを使用して)ノードオブジェクトを生成し、それをデータベースにマージします(私はJPAに仕事をさせたいと思っていました)。

今、私はLUNなしでいくつかのテストを行った。

public void updateNode(Node node) { 
    if (!nodeInDB(node)) { 
     LOGGER.log(Level.INFO, "persisting node {0} the first time", node.toString()); 
     em.persist(node); 
    } else { 
     LOGGER.log(Level.INFO, "merging node {0}", node.toString()); 
     node = em.merge(node); 
    } 
} 

テスト:

@Test 
public void addTest() throws Exception { 
    Node node = new Node(); 
    node.setName("hostname"); 
    node.setSerial("serial"); 
    nodeManager.updateNode(node); 
    nodeManager.updateNode(node); 
    node.setName("newhostname"); 
    nodeManager.updateNode(node); 
} 

これは@Versionフィールドなしで動作し、私はステートレスEJBの以下のサービスを提供しています。 @Versionフィールドでは、私はOptimisticLockExceptionを取得します。

これは間違ったアプローチですか?常にem.find(...)を実行してから、getterとsetterで管理対象エンティティを変更する必要がありますか?

何か助けていただければ幸いです。

BR Rene

答えて

1

オプティミスティックロックを有効にするには、@versionアノテーションを使用します。

オプティミスティック・ロックを使用すると、テーブルへの書き込みが成功するたびにバージョン・カウンタが増加します。バージョン・カウンタは、エンティティを永続化するたびに読み取られ、比較されます。書き込み時にエンティティがテーブルのバージョンと一致しないことが最初に判明したときに読み取られたバージョンの場合、例外がスローされます。

プログラムは、バージョン列を1度だけ読み取った後にテーブルを何度も更新します。したがって、2回目にpersist()またはmerge()を呼び出すと、バージョン番号が一致せず、クエリが失敗します。これは、オプティミスティック・ロックを使用する場合に予期される動作です。最初に読んだときから変更された行を上書きしようとしていました。

あなたの最後の質問に答えてください:データベースに書き込むたびに、変更されたバージョン情報を読む必要があります。 em.refresh()を呼び出すことでこれを行うことができます。

しかし、あなたの戦略を再考することを検討してください。オプティミスティック・ロックは、トランザクションで最もよく使用され、ユーザーが変更を実行している間にデータの一貫性を保証します。これらは通常、データを読み取ってユーザーに表示し、変更を待ってから、ユーザーがタスクを完了した後にデータを保持します。このコンテキストでは、同じデータ行を複数回書く必要はありません。これらの書き込み呼び出しのたびにオプティミスティック・ロックが発生するため、トランザクションが失敗する可能性があります。

+0

私はそれを理解していません。私はまだランチを追加していませんでした。 – reen

+0

申し訳ありませんが、私は明らかに十分に読んでいませんでした。私はあなたの答えを変えました。 – weltraumpirat

+0

ありがとうございました。そのシナリオでバージョン管理を完全に削除することを提案していますか?クライアントソフトウェアは、一度に1つのノードだけが更新されることを保証する必要があります。 – reen

関連する問題