0

私の Web アプリケーションでは、多くの場合、1 回のリクエストでエンティティをデータベースから読み取ったままにし、後で別のリクエストでエンティティを更新する必要があります。現在、私はヘルパーメソッドを持っています

protected <T> T refresh(T t) {
    if (!entityManager.contains(t)) {
        t = merge(t);
        entityManager.refresh(t);
    }
    return t;
}

各メソッドは、他の何よりも先に、作業中のエンティティを更新します。エンティティが既に更新されている場合、何も起こりません。

これはうまく機能しましたが、後でこのソリューションには重大な問題があることに気付きました。エンティティがデータベースで同時に変更されている場合、への呼び出しが失敗します。merge明らかに、 の内容がの即時呼び出しによって置き換えられることmergeを「知る」ことはできません。trefresh

この問題の適切な解決策は何でしょうか? これまでのところ、次のようなアイデアがありますが、完全に満足できるものはありません。

  1. mergeandを呼び出す代わりにrefresh、エンティティの ID を取得して呼び出す

    t = find(theClassOfT, t.getId());
    

    これで問題は解決します。完全に新しいエンティティが得られますが、大きな欠点があります。クラスTと ID を知る必要があります。ID の取得は、すべてのエンティティの最上位のスーパー インターフェイスを持つことで実現できますが、クラスの取得には問題があります (JPA 実装はエンティティをサブクラス化する可能性があるため、呼び出すとt.getClass()の実装固有のサブクラスが返されるのではないかと心配していTます)。

  2. 長期的には ID のみを保持し、各リクエスト中にエンティティを最新に読み取ります。これは、設計の観点からはより正しいように見えますが (古いエンティティはとにかく無効な情報を保持しています)、ここでも のクラスをT手元に用意する必要があります。

更新:リクエスト全体でエンティティを保持している理由は、単に便宜上のためです。その間エンティティが変更されていないことを確認する必要は特にありません-とにかく、次のリクエストでエンティティを更新します。

4

3 に答える 3

1

あなたの#1はうまくいくはずです。

object.getClass()使用できる Id のクラスで機能するはずですemf.getPersistenceUnitUtil().getIdentifier(object)

Mapまた、操作にプロパティを渡すことはできずfind()、更新クエリのヒント ("eclipselink.refresh"="true" または"javax.persistence.cache.storeMode", "REFRESH" ) を含めることができます。これにより、潜在的な 2 つのクエリを回避できます。 .

于 2013-08-14T14:58:49.073 に答える
0

データベースからエンティティを更新しようとしている場合は、おそらく何か問題があります。

エンティティは、必要以上に長く存続するべきではありません。JPA プロバイダーはキャッシュを処理する必要があるため、同じクエリを呼び出して同じエンティティを再度取得することは、それほど面倒なことではありません。したがって、エンティティを @RequestScoped、@ConversationScoped および同様のスコープに保存します。

一方、エンティティが長期間必要な場合は、ロックを検討する必要があります。前のポスターが説明したように、次のいずれかを実行できます。

  • 悲観的ロック。エンティティをロックし、コミットする前に他の人がそれを更新できないようにします
  • 楽観的ロック、エンティティが更新されないことを期待しますが、save()誰かが失敗する可能性があります

たとえば、ロックと JPA の詳細については、http: //city81.blogspot.com/2011/03/pessimistic-and-optimistic-locking-in.htmlを参照してください。

于 2013-08-14T10:00:27.800 に答える