JPA(eclipselink)を使用してデータベースからデータを取得したい。データベースは他の多くのソースによって変更されているため、実行するたびにデータベースに戻ります。キャッシュを無効にすることに関する多くの投稿を読みましたが、これは機能していないようです。何か案は?
次のコードを実行しようとしています:
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("default");
EntityManager em = entityManagerFactory.createEntityManager();
MyLocation one = em.createNamedQuery("MyLocation.findMyLoc").getResultList().get(0);
MyLocation two = em.createNamedQuery("MyLocation.findMyLoc").getResultList().get(0);
System.out.println(one==two);
one == twoはtrueですが、falseにしたいです。
Persistence.xmlにそれぞれ以下を追加しようとしました。
<property name="eclipselink.cache.shared.default" value="false"/>
<property name="eclipselink.cache.size.default" value="0"/>
<property name="eclipselink.cache.type.default" value="None"/>
また、エンティティ自体に@Cacheアノテーションを追加しようとしました。
@Cache(
type=CacheType.NONE, // Cache nothing
expiry=0,
alwaysRefresh=true
)
私は何かを誤解していますか?
この動作は正しいです。それ以外の場合、オブジェクト1とオブジェクト2を異なる値で変更すると、永続化するときに問題が発生します。起こっているのは、オブジェクト2をロードする呼び出しです。最初の呼び出しでロードされたエンティティを更新します。これらは同じオブジェクトであるため、同じオブジェクトを指している必要があります。これにより、ダーティデータを書き込むことができなくなります。
2つの呼び出しの間にem.clear()を呼び出すと、エンティティ1は切り離され、チェックはfalseを返します。ただし、その必要はありません。Eclipseリンクはデータを最新に更新しているので、頻繁に変更されるため、これはあなたが望むものです。
JPAを使用してこのデータを更新する場合は、エンティティで pessimistic locks を取得して、基になるデータがDBで変更できないようにする必要があります。
キャッシュオプションは、クエリキャッシュではなくオブジェクトキャッシュを削除するだけであったため、クエリキャッシュを無効にする必要があります。そのため、新しい結果が得られません。
あなたのコードで:
em.createNamedQuery("MyLocation.findMyLoc").setHint(QueryHints.CACHE_USAGE, CacheUsage.DoNotCheckCache).getResultList().get(0);
またはpersistence.xmlで:
<property name="eclipselink.query-results-cache" value="false"/>
final Query readQuery = this.entityManager.createQuery(selectQuery);
readQuery.setParameter(paramA, valueA);
// Update the JPA session cache with objects that the query returns.
// Hence the entity objects in the returned collection always updated.
readQuery.setHint(QueryHints.REFRESH, HintValues.TRUE);
entityList = readQuery.getResultList();
これは私のために動作します。
ベンダー固有にせずにキャッシュを無効にしたい場合は、ドメインオブジェクトに次の注釈を付けることができます。
@Cacheable(false)
以下に例を示します。
@Entity
@Table(name="SomeEntity")
@Cacheable(false)
public class SomeEntity {
// ...
}
見る、
http://wiki.Eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching
同じEntityManagerの場合、JPAは常にone == twoを必要とするため、キャッシュオプションに関係なくこれは正しいです(これは、トランザクションの分離を強制し、オブジェクトIDを維持するL1キャッシュまたはトランザクションキャッシュです)。
クエリを強制的に更新(および行った変更を元に戻す)するには、クエリヒント "eclipselink.refresh" = "true"を使用できます。またはおそらく、クエリ/リクエストごとに新しいEntityManagerを使用するか、EntityManagerでclear()を呼び出してください。
<property name="eclipselink.cache.shared.default" value="false"/>
共有キャッシュ(L2キャッシュ)を無効にする正しい方法です。他の設定はすべて正しくなく、問題を引き起こす可能性があるため、すべて削除してください。
EclipseLinkはデフォルトではクエリキャッシュを維持しないため、これらの設定は影響しません。 CacheUsageも正しくありません。これを使用しないでください(メモリ内クエリ用です)。
オブジェクトの属性(MyLocationなど)を手動で変更する場合。上記のトリック(CACHE_USAGE=CacheUsage.DoNotCheckCache
、またはeclipselink.query-results-cache=false
)は、私が試みたようには機能しないようです。
そこで、eclipselink.refresh
という別のヒントをtrue
に設定しようとしました。その後、動作します。つまり、手動で変更された属性が取得されます。
私が理解しているように、上記のトリックは正しいオブジェクトを取得することを保証するだけです。ただし、オブジェクトが既にキャッシュされている場合、Eclipselinkはオブジェクトのコンテンツの鮮度をチェックせずにオブジェクトを返します。ヒントeclipselink.refresh
がtrue
に設定されている場合のみ、これらのオブジェクトは最新の属性値を反映するように更新されます。
一次キャッシュはデフォルトで有効になっており、無効にすることはできません。つまり、persistence.xmlファイルの設定は一次キャッシュを無効にしません。
を呼び出すことによってのみ、すべてのエンティティマネージャオブジェクトをクリアできます。
entityManager.clear()
これにより、後続のクエリがデータベースに(最初に)送られ、オブジェクトが再びキャッシュに保存されます
を呼び出すことで、各クエリをデータベースに直接移動させることができます
query.setHint("javax.persistence.cache.storeMode", CacheStoreMode.REFRESH);
この投稿は古いかもしれませんが、助けが必要な人のために書いています。私はこの問題を抱えていて、最終的にこのコードで解決しました:
em.createNamedQuery("findAll").setHint(QueryHints.CACHE_RETRIEVE_MODE, CacheRetrieveMode.BYPASS).getResultList();
本当にうまくいきます。また、BYPASS列挙型のjavadocを見ると、次のように記述されています。
キャッシュをバイパスする:データベースから直接データを取得します。
JPA実装としてWeblogic 12cとTopLinkを使用していることに気付くはずです。