【发布时间】:2013-02-07 02:40:10
【问题描述】:
我正在使用 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;
}
注意:我保持上面的代码简洁:拦截器注释接受一个类对象作为它的参数,我使用类对象来查找它的所有 NamedQueries 的名称,其中有一个 QueryHint 指示它们已被缓存。这只是为了解释我如何找到要清除的命名查询。
拦截器方法不起作用,我不知道为什么。 我知道invalidateCacheForQuery(String namedQueryName) 方法在我得到正确的日志消息时也会被拦截器方法调用(使用正确的命名查询名称)。我还从拦截器中获取日志消息。因此拦截器机制正在工作,例如这不是 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 的查询结果缓存无效。我通过日志记录验证了两种方法都设法使用相同的参数(NamedQuery 名称)调用该方法。内联“在 em.persist() 之后”方式有效,但在拦截器中执行基本完全相同的事情却没有。感觉就像我正在使用拦截器清除 EclipseLink 缓存的另一个实例,但我不知道这怎么可能。
【问题讨论】:
-
你的 EJB 是无状态的还是有状态的?
-
一切都是无状态的。
-
您可能正在清除会话 bean 的另一个实例。
标签: jakarta-ee jpa eclipselink cdi interceptor