如何在不同字段/密钥上使用缓存与查询



我正在实现基于Spring MVC的Web应用程序,我添加了缓存,但是现在在将更改应用于基础数据库时如何在缓存上操作。p>我一直在研究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();
   }
}

我正在使用自定义键机,所以我知道调用方法时如何生成键:

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();
   }
}

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

对于商店方法,我发现问题很容易解决:

 ...
 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);
    }
 }

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

这是我到目前为止提出的一个实现,但似乎比应该复杂得多(昂贵)。如果我的设计模式正确,或者是否应该以其他方式解决我的问题,任何人都有任何有价值的输入?

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以这种方式工作。

使用EHCACHE搜索API,在操作员中可能对您有用。

最新更新