我正在实现一个基于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,所以我知道调用方法时如何生成键:

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就是这样。

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

10-11 04:58
查看更多