给定这些实体和存储库来访问 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(Long customerId) 添加缓存,这样,当为客户添加一些购买时,只有该客户的购买被驱逐。
相关的依赖项是:
<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;
}
}
由于 spring 缓存(和 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;
}
}
并将 Spring 缓存添加到我的存储库方法中:
@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);
}
我使用这种方法遇到的唯一问题是使用 Spring 表达式评估 key 。
有什么方法可以实现这一点,或者有其他可行的方法吗?
最佳答案
为每条客户记录创建缓存有点过分了。使用 SpEL,您可以指定要驱逐的客户记录的 key 。配置ehcache,使之有1个客户缓存。然后,您更改PurchaseDAO 方法,以便它们指定要缓存或逐出的 key 。更改您的代码如下
@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 获取 customerId 的问题,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;
}
关于java - 是否可以逐出spring缓存部分数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37242162/