2013-02-21 79 views
4

我使用的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的另一个缓存实例,但我不知道这是怎么可能的。

+0

您的EJB是无状态的还是有状态的? – LightGuard 2013-02-22 17:56:14

+0

一切都是无状态的。 – 2013-02-25 07:02:19

+0

可能你正在清除会话bean的不同实例。 – LightGuard 2013-02-25 16:47:12

回答

1

您的问题是,您在使用Interceptor方法时正在处理两种不同的PersistenceContext。

看起来您的拦截器配置在实体级别上工作,该级别不共享EJB容器的PersistenceContext。尝试将拦截器移至服务层(将其应用于持久/修改数据的EJB)。它不像你想要做的那样自动化,但应该工作。