Как использовать кеш с запросами по разным полям / ключам?

Я реализую веб-приложение на основе Spring MVC, где я добавил кеширование, но теперь сталкиваюсь с проблемой, связанной с тем, как работать с кешем, когда изменения применяются к базовой базе данных.

Я изучал документацию, доступную на 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();
   }
}

Очевидная проблема, которую мне нужно решить, - это как реализовать политику модификации кэша, когда данные добавляются или удаляются в базовую базу данных.

Для метода 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);
    }
 }

Но для методов удаления все становится намного сложнее.

Это одна из реализаций, которую я придумал до сих пор, но она кажется намного более сложной (дорогой), чем должна быть. У кого-нибудь есть ценный вклад, если мои шаблоны проектирования верны, или если должны решить мою проблему каким-либо другим способом?

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

Возможно, это правильный способ ее решения? Я не наткнулся на какие-либо рецепты, которые решают эти проблемы, поэтому я предпочитаю здесь.

2 ответа

Используйте API поиска Ehcache, вероятно, в операторе будет полезно в вашем случае.

Я выскажу свое мнение. Кажется, это (почти) правильный подход. Я думаю, что после операции удаления вы должны очистить весь кэш и начать заново. Обычно после операций по изменению данных кэш сбрасывается. Это сделано из-за объединения таблиц. Кажется, это не ваш случай, потому что у вас есть только два запроса и нет объединений, но обычно кэш очищается и перезапускается. При этом вам не нужно сканировать кеш, который ссылается на "fieldBeta" после изменений в "fieldAlfa". Надеюсь, что-нибудь из этого поможет вам. Кстати, MyBatis работает именно так.

Другие вопросы по тегам