2016-05-15 68 views
0

鉴于这些实体和访问资源库中DDBB他们的数据:是否可以驱逐弹簧缓存部分数据?

@Entity 
public class Customer { 
Long id; 
} 

@Entity 
public class Purchase { 
    Long customerId; 
} 

@Repository 
public lass PurchaseDAO { 

    public void insert(Purchase insert); 

    public void deleteCustomerPurchases(Long customerId); 

    public long getTotalPurchasesAmount(Long customerId); 

    public long getTotalPurchasesAmountPerMonth(Long customerId, int month); 
} 

我想补充的方法getTotalPurchaseAmounts(龙客户ID)高速缓存,在这样的方式,增加了一些购买时一个客户,只有purchasesd的客户被驱逐。

的相关Dependance的条目是:

 <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-beans</artifactId> 
      <version>4.2.3.RELEASE</version> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-context</artifactId> 
      <version>4.2.3.RELEASE</version> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-context-support</artifactId> 
      <version>4.2.3.RELEASE</version> 
     </dependency> 
     <dependency> 
      <groupId>net.sf.ehcache</groupId> 
      <artifactId>ehcache</artifactId> 
      <version>2.10.2</version> 
     </dependency> 

相关配置:

@EnableCaching 
@Configuration 
public class CommonConfig { 

    @Bean 
    public CacheManager cacheManager() { 
     EhCacheCacheManager cacheManager = new EhCacheCacheManager(); 
     cacheManager.setCacheManager(ehCacheManager().getObject()); 
     return cacheManager; 
    } 

    @Bean 
    public EhCacheManagerFactoryBean ehCacheManager() { 
     EhCacheManagerFactoryBean ehcache = new EhCacheManagerFactoryBean(); 
     ehcache.setConfigLocation(new ClassPathResource("ehcache.xml")); 
     return ehcache; 
    } 

} 

作为弹簧缓存(和ehcache的)逐出被限制为每个元素或所有项,我已开发的解决方案是创建缓存(每个客户一个缓存),所以我可以驱逐这些缓存。

扩展点我认为是最好的,这是实现自定义CacheResolver:

@Component("CustomerPurchasesCacheResolver") 
public class CustomerPurchasesCacheResolver implements CacheResolver { 

    @Autowired 
    private EhCacheCacheManager cacheManager; 

    @Override 
    public Collection<? extends Cache> resolveCaches(CacheOperationInvocationContext<?> context) { 
     String cacheName = "customerPurchases_" + getCustomerId(context); 
     // Add cache to cacheManager if it does not exists 
     cacheManager.getCacheManager().addCacheIfAbsent(cacheName); 

     Set<Cache> caches = new HashSet<>(); 
     caches.add(cacheManager.getCache(cacheName)); 
     return caches; 
    } 

    // Retrieves customerId from cache operation invocation context; 
    private Long getCustomerId(CacheOperationInvocationContext<?> context) { 
    String key = ((CacheOperation) context.getOperation()).getKey(); 
     // TODO Evaluate key 
     // HOW CAN I DO THIS???????????? 
     return null; 
    } 

} 

,并添加春天缓存到我的仓库方法:

@Repository 
public lass PurchaseDAO { 

    @CacheEvict(cacheResolver="CustomerPurchasesCacheResolver", key="#purchase.customerId")  
    public void insert(Purchase purchase); 

    @CacheEvict(cacheResolver="CustomerPurchasesCacheResolver", key="#customerId")  
    public void deleteCustomerPurchases(Long customerId); 

    @Cacheable(cacheResolver="CustomerPurchasesCacheResolver") 
    public long getTotalPurchasesAmount(Long customerId); 

    @Cacheable(cacheResolver="CustomerPurchasesCacheResolver") 
    public long getTotalPurchasesAmountPerMonth(Long customerId, int month); 

} 

唯一的问题我开始使用这种aproach是为了得到使用Spring Expresions评估的关键。

有什么办法可以得到这个或不同的方法可以工作吗?

回答

2

它为每个客户记录创建缓存的矫枉过正。使用SpEL,您可以为客户记录指定一个密钥来驱逐。配置ehcache,以便有一个客户缓存。然后,您更改您的PurchaseDAO方法,以便指定要缓存或驱逐的密钥。更改您的代码如下

@CacheEvict(value = "customerCache" , key="#purchase.customerId")  
public void insert(Purchase purchase); 

@Cacheable(value = "customerCache" ,key = "#customerId") // you can omit the key if using default key generator as it still uses the method argument 
public long getTotalPurchasesAmount(Long customerId); 

但是回答你的问题有关从CacheResolver获得客户ID,CacheOperationInvocationContext有getArgs()方法返回传递给方法的参数被缓存。

private Long getCustomerId(CacheOperationInvocationContext<?> context) { 
     Object[] args = context.getArgs(); 
     Object firstArg = args[0]; 
     if(firstArg instanceof Long){ 
      return (Long)firstArg; 
     } 
     else if(firstArg instanceof Purchase){ 
      Purchase purchase = (Purchase)firstArg; 
      return purchase.getCustomerId(); 
     } 
     return null; 
    } 
+0

谢谢Ekem。问题是每个客户将会有多个记录(即@Cacheable public int getPurchasesAmountPerMonth(int month)),以及具有不同签名的方法来驱逐缓存,因此获取参数[0]不会完成这项工作。你让我意识到我最初的问题缺乏关键信息。我将编辑这个问题以表明这个想法是问题的主要观点。 – Basa