2016-05-13 2 views
3

У меня есть два метода для получения объекта с двумя разными параметрами. У меня также есть метод сохранения, который использует один из этих параметров. Как я могу выдворить сущность из кеша под обеими ключами извлечения? например см. ниже:Весеннее кэширование/репозиторий пружин, выселение нескольких ключей

@Cacheable 
public User getByUsername(String username); 

@Cacheable 
public User getByEmail(String email); 


@CacheEvict(key="#entity.username") 
User save(User entity); 

В приведенном выше обращении к getByEmail будет возвращена устаревшая дата.

ответ

6

Существует несколько вариантов, конечно, но, как обычно, Весна имеет заднюю часть.

Самый простой и самый простой подход заключается в привлечении @Caching аннотацию Spring на вашем методе save, как так ...

@Caching(evict = { 
    @CacheEvict(cacheNames = "Users", key="#user.name"), 
    @CacheEvict(cacheNames = "Users", key="#user.email") 
}) 
User save(User user); 

Для справки, я создал класс пример тест демонстрирует эту рабочую here.

Вы заметите, что я подражал вашему примеру выше, используя Spring's Аннотации кэш-абстракции на моем UserRepository. В этом случае мое репо поддерживается Pivotal GemFire ​​, но любое хранилище данных будет работать. Я использую ConcurrentMap в качестве моего провайдера кэширования, используя Spring ConcurrentMapCacheManager, но, конечно же, любой поставщик кеширования будет делать.

Мои test case доходы сэкономить новыйUser, гарантируя, что пользователь хранится еще не кэшируются. Затем в результате теста выполняются методы запросов (findByName, findByEmail), гарантирующие, что пользовательский объект кэшируется соответствующим образом в каждом случае. Затем я удаляю объект из основного хранилища данных и гарантирую, что объект все еще кэшируется. И, наконец, момент истины, я изменяю объект, повторно сохраняю объект, утверждая, что объект хранится в этом все записей были «выселены» из кеша.

Вы также можете попробовать, а другой оптимизации, чтобы объединить @CachePut аннотацию с 2 @CacheEvict аннотаций в этом случае, что может восстановить кэш на основе новой, обновленной сущности, что-то вроде ...

@Caching(
    evict = { 
    @CacheEvict(cacheNames = "Users", key="#a0.name", beforeInvocation = true), 
    @CacheEvict(cacheNames = "Users", key="#a0.email", beforeInvocation = true) 
    }, 
    put = { 
    @CachePut(cacheNames = "Users", key="#result.name"), 
    @CachePut(cacheNames = "Users", key="#result.email") 
    } 
) 
User save(User user); 

Примечание: обратите внимание пользователя атрибута на @CacheEvict аннотациях beforeInvocation вместе с @CachePuts

Однако, вы можете предпочесть, что объект будет лениво добавлены в кэш на основе необходимости.

Хотя вы бы предположили, что объект часто обращается/используется с тех пор, как метод save на вашем репо был просто вызван и поэтому полагается на ваш базовый хранилище данных (например, GemFire), чтобы установить дополнительное выселение (основанное на переполнении)/expiration (на основе LRU), тем самым улучшая управление системными ресурсами (например, памятью), сохраняя при этом оптимальную производительность приложения.

Пища для размышлений.

Надеюсь, это поможет.

+0

Спасибо, это хорошо выглядит. Вопрос: в чем разница между # a0, # a1, ... и # p0, p1, ... и с использованием параметра метода var name 'user'.(На самом деле, я не могу заставить имя параметра работать в SpEL, я получаю сообщение об ошибке: «имя поля поля свойства не может быть найдено на null», нуль - объект). – Saul

+0

Другая мысль: хотя кажется, что имеет смысл использовать # result.name и result.email для предварительного заполнения кеша, я беспокоюсь о проблемах параллелизма, используя beforeInvocation = true. Возможно, было бы безопаснее просто @CachePut (key = "# a0.name") и т. Д., То есть влияние и вероятность реализации() реализаций, фактически изменяющих значения по сравнению с воздействием и вероятностью проблемы параллелизма. – Saul

+0

И еще один вопрос: в приведенном выше примере свойство электронной почты может быть или не быть нулевым. Это не будет работать с некоторыми реализациями кеша (например, concurrentHashMap). Мне жаль, что не было параметра «ignoreNullKeys», который я могу установить в false, что в свою очередь не выполняет вызовы «doEvict» или «put» на клавишах с нулевыми значениями. – Saul

Смежные вопросы