当前位置: 首页 > 知识库问答 >
问题:

是否可以逐出spring缓存部分数据?

司空兴为
2023-03-14

鉴于这些实体和存储库可以访问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(长customerId)添加缓存,这样,当为客户添加一些购买时,只有该客户的purchasesd被逐出。

相关的依赖项是:

        <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)逐出的次数受元素或所有条目的限制,我开发的解决方案是通过友好方式创建缓存(每个客户一个),这样我就可以逐出这些缓存。

我认为最好的扩展点是实现自定义缓存解析器:

@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表达式计算键。

有什么方法可以得到它或者另一种方法可以奏效吗?

共有1个答案

斜高翰
2023-03-14

为每个客户记录创建缓存是一种过分的做法。使用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获取CusterId的问题,CacheOPationInvocationContext有一个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;
    }
 类似资料:
  • 我有一个关于内存系统遵循的策略的基本问题。 考虑一个具有私有L1和L2缓存的核心。在L2缓存之后,我们有一个相干流量运行的总线。现在,如果从L2高速缓存中逐出地址(X)的高速缓存行,是否有必要从L1高速缓存中逐出该地址?? 逐出的原因可能是它有助于保持一致性协议的不变[如果l2中的一行显示无效,则此核心不包含此地址]。

  • 我使用Spring缓存抽象,定义了多个缓存。有时,当数据更改时,我想逐出多个缓存。是否可以使用Spring的CacheExit注释逐出多个缓存?

  • 在中可以实现这样的功能吗 注意这里A是部分着色的。 我知道光凭类是不可能的。(文本显示在) 要实现这一点,有什么解决方案可以单独使用Swing或必须使用CSS? 编辑: 如果这是不可能的摆动,任何解决方案与以下标签?

  • 在我的项目中,我使用了一个@Cacheable注释ia一个服务方法,它返回涉及书籍和一些标记的计算结果,我想在一个@Controller类方法中退出缓存,该方法将一本新书添加到数据库中,因为这本新书将是新计算所必需的。 服务类:@Cacheable("metas") 控制器类:@RequestMapping@CacheEvict(value=“metas”,allEntries=true)

  • 问题内容: 我正在尝试在tableView之类的Instagram,vine甚至Facebook中下载和播放视频。 我想要实现的是一个tableView,在其中显示视频,它们会在滚动时自动下载和播放。像Instagram … 到目前为止,我已经完成了大部分工作,但是我想更改的事实是,每次查看单元格时,视频都会一次又一次下载....当然,必须有一种缓存视频或仅下载视频的方法相同的视频一次。…就像对S

  • 我想为Spring Cache执行以下操作。 > 检查传递的字符串是否存在于缓存中。如果存在,则返回true,如果不存在,则添加到缓存;checkInCache(字符串str) 从缓存逐出字符串(String str) 尝试如下 @组件公共类FlightCache{ 并在配置类上添加了@EnableCaching注释。 错误: