java - 如何在不同字段/键上的查询中使用缓存?

标签 java spring caching ehcache evict

我正在实现一个基于 Spring MVC 的 Web 应用程序,其中添加了缓存,但现在面临一个问题,即当更改应用于底层数据库时如何操作缓存。

我一直在研究 Ehcache ( http://ehcache.org/documentation ) 上提供的文档,但未能找到任何好的示例来解决我的问题。

假设我有一个 DAO 类,我选择在两个返回对象列表的方法上应用缓存(不可编译的伪代码):

@Repository
public class MyEntityDao {

   @Autowired
   DataSource ds;

   @Autowired
   EhCacheCacheManager cacheManager;

   @Autowired
   CacheKeyGenerator keyGenerator;

   @Cacheable("myEntityCache")
   public List<MyEntity> findByFieldAlpha(String fieldAlpha) {
       return ds.query("select * from MyEntity where fieldAlpha = #fieldAlpha").execute();
   }

   @Cacheable("myEntityCache")
   public List<MyEntity> findByFieldBeta(String fieldBeta) {
       return ds.query("select * from MyEntity where fieldBeta = #fieldBeta").execute();
   }

   public void deleteByFieldAlpha(String fieldAlpha) {
      ds.query("delete from MyEntity where fieldAlpha = #fieldAlpha").execute();
   }

   public void deleteByFieldBeta(String fieldBeta) {
      ds.query("delete from MyEntity where fieldBeta = #fieldBeta").execute();
   }

   public void store(MyEntity myEntity) {
      ds.insert(myEntity).execute();
   }
}

我正在使用自定义 KeyGenerator,因此我知道调用方法时如何生成 key :

public class CacheKeyGenerator implements KeyGenerator {

   @Override
   public Object generate(final Object target, final Method method, final Object... params) {
       return generateCacheKey(method.getName(), params);
   }

   public String generateCacheKey(final String methodName, final Object... params) {
       StringBuilder key = new StringBuilder();
       key.append(methodName);
       for (Object o : params) {
          key.append("_").append(o.toString());
       }
       return key.toString();
   }
}

我需要解决的明显问题是当向底层数据库添加或删除数据时,如何实现缓存修改策略。

对于 store 方法,我发现这个问题很容易解决:

 ...

 public void store(MyEntity myEntity) {
    boolean success = ds.insert(myEntity).execute();
    if (success) {
       Cache cache = cacheManager.getCache("myEntityCache")

       String keyFieldAlpha = keyGenerator.generateCacheKey("findByFieldAlpha", myEntity.getFieldAlpha());
       List cacheListFieldAlpha = (List) cache.get(keyFieldAlpha).getObjectValue();
       cacheListFieldAlpha.add(myEntity);

       String keyFieldBeta = keyGenerator.generateCacheKey("findByFieldBeta", myEntity.getFieldBeta());
       List cacheListFieldBeta = (List) cache.get(keyFieldBeta).getObjectValue();
       cacheListFieldBeta.add(myEntity);
    }
 }

但是对于删除方法,事情会变得更加复杂。

这是我迄今为止提出的一个实现,但它似乎比应有的要复杂(昂贵)得多。如果我的设计模式正确,或者是否应该以任何其他方式解决我的问题,任何人都可以提供任何有值(value)的意见吗?

public void deleteByFieldAlpha(String fieldAlpha) {
  List<MyEntity> myEntititesToBeDeleted = this.findByFieldAlpha(fieldAlpha);
  boolean success = ds.query("delete from MyEntity where fieldAlpha = #fieldAlpha").execute();
  if (success) {
     Cache cache = cacheManager.getCache("myEntityCache")

     String keyFieldAlpha = keyGenerator.generateCacheKey("findByFieldAlpha", fieldAlpha);
     cache.remove(keyFieldAlpha);

     for (MyEntity myEntity : myEntititesToBeDeleted) {
        String keyFieldBeta = keyGenerator.generateCacheKey("findByFieldBeta", myEntity.getFieldBeta());
        List cacheListFieldBeta = (List) cache.get(keyFieldBeta).getObjectValue();
        cacheListFieldBeta.remove(myEntity); 
     }
  }
}

也许这是解决问题的正确方法?我还没有偶然发现任何解决这些问题的食谱,所以我在这里做出了最好的猜测。

最佳答案

我给你我的意见。这似乎是(几乎)正确的方法。我认为删除操作后您应该清空所有缓存并重新开始。通常,在数据更改操作之后,缓存会被重置。这是因为表连接而完成的。似乎不是你的情况,因为你只有两个查询并且没有联接,但通常缓存会被清理并重新启动。通过这种方式,您不需要在“fieldAlfa”更改后扫描引用“fieldBeta”的缓存。希望本文中的一些内容可以帮助您。 顺便说一句,MyBatis 就是这样工作的。

关于java - 如何在不同字段/键上的查询中使用缓存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21484533/

相关文章:

java - 为什么我们要在 Spring Boot 中更改 servlet 上下文路径?

java - 使用 springframework 验证错误验证枚举

java - android可运行差异

java - Servlet 响应应该被缓存,但没有

java - 参数类型的运算符 < 未定义

java - 基于属性或基于构造函数的依赖注入(inject)

node.js - Node.js 服务器中没有缓存

ios - 以只读方式刷新解析本地数据存储

java - 如何将 boolean 返回值调用到其他方法中?

java - 将值从 html 页面传递到 java 类的最佳方法是什么?