私はEclipseLinkのクエリ結果キャッシュを使用しています:
@NamedQuery(name = "User.findAll",
query = "SELECT s FROM ...",
hints= {
@QueryHint(name=QueryHints.QUERY_RESULTS_CACHE, value=HintValues.TRUE)
...
最初に、次のメソッドを持つ「CacheManager」という名前のステートレス Bean を使用して、手動でキャッシュをクリアしました。
public void invalidateCacheForQuery(String namedQueryName) {
log.info("CacheManagerService: clearing cache for named query " + namedQueryName);
((JpaCache) em.getEntityManagerFactory().getCache())
.clearQueryCache(namedQueryName);
}
クエリ結果を無効にする可能性のある変更 (追加/削除) があった場合は常に、このメソッドを呼び出します。呼び出しは、変更の直後に行われました。
em.merge(u);
cacheMan.invalidateCacheForQuery("..."); // for each cached query
(私はここで少し手抜きをしています。これが私がやっていたことの本質です)。
上記の解決策はうまくいきました - キャッシュがクリアされないと失敗するJUnitテストがあり、上記の「invalidateCacheForQuery」呼び出しが存在する場合は失敗しません(存在しない場合は失敗します)。
次に、インターセプターを定義して生活を楽にしようとしました。
@EJB CacheManager cacheMan;
@AroundInvoke
public Object clearQueryCacheAfterwards(InvocationContext ctx)
throws Exception {
// this does something like em.persist that might make cached query results
// invalid:
final Object result = ctx.proceed();
// hera are calls cacheMan.invalidateCacheForQuery for all of the relevant named
// queries. Yes, this is done after ctx.proceed().
return result;
}
注: 上記のコードは簡潔にしました。インターセプター アノテーションは Class オブジェクトをパラメーターとして受け入れ、クラス オブジェクトを使用して、キャッシュされたことを示す QueryHint を持つすべての NamedQueries の名前を見つけました。これは、クリアする名前付きクエリを見つけた方法を説明するためのものです。
インターセプターのアプローチは機能しません。その理由はわかりません。正しいログ メッセージを取得するため、Interceptor アプローチでも (正しい名前のクエリ名を使用して)メソッドが呼び出されることはわかっています。invalidateCacheForQuery(String namedQueryName)
インターセプターからログ メッセージも取得します。そのため、Interceptor メカニズムは機能しています。たとえば、beans.xml に定義がないなどの単純な問題ではありません。ただし、キャッシュをまったくクリアしなかった場合と同じように JUnit テストが失敗するため、キャッシュのクリアが機能しないことはわかっています。
ログを見ると、これらの連続する行により、インターセプターが本来の動作をしていることを確認できます。
ClearQueryCacheInterceptor: clearing query cache for named query User.findAll
CacheManagerService: clearing cache for named query User.findAll
@PersistenceContext(unitName="...") EntiytyManager em;
また、インターセプターで使用して、CacheManager EJB を使用せずにキャッシュをクリアしようとしました。
長い説明を要約すると、EclipseLink のクエリ結果キャッシュを無効にする同じメソッドを呼び出す 2 つのアプローチがあります。両方のアプローチが同じパラメーター (NamedQuery 名) を使用してそのメソッドを呼び出すことができることをロギングによって確認しました。インラインの「em.persist() の後」の方法は機能しますが、インターセプターで本質的にまったく同じことを行うと機能しません。インターセプターを使用してEclipseLinkのキャッシュの別のインスタンスをクリアしているように感じますが、それがどのように可能になるかはわかりません。