我使用的EclipseLink的查询结果缓存:如何清除CDI拦截器中的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);
}
我只要有可能使查询结果过时的修改(添加/删除),d就会调用这个方法。呼叫是在修改后直接进行的,例如,
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;
}
注:我一直在上面的代码简洁:拦截器注解接受了类对象作为参数,我用类对象找到其所有具有QueryHint指示它们被缓存的NamedQueries的名称。这只是为了解释我如何找到清楚的命名查询。
拦截器方法不起作用,我不知道为什么。 我知道方法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 。
回想一下lenghty的解释:我有两种方法调用相同的方法,使EclipseLink的查询结果缓存失效。我通过日志记录验证了这两种方法都可以使用相同的参数(NamedQuery名称)来调用该方法。内嵌“后em.persist()”的方式工作,但在拦截器中做基本完全相同的事情不会。这种感觉好像我正在用拦截器清理EclipseLink的另一个缓存实例,但我不知道这是怎么可能的。
您的EJB是无状态的还是有状态的? – LightGuard 2013-02-22 17:56:14
一切都是无状态的。 – 2013-02-25 07:02:19
可能你正在清除会话bean的不同实例。 – LightGuard 2013-02-25 16:47:12