@Cacheable: сначала определить пакет
В Java-приложении встречаются две разные аннотации с одинаковым коротким именем.
| Полное имя | Что кэшируется |
|---|---|
jakarta.persistence.Cacheable | экземпляры JPA-сущности во втором уровне кэша provider-а |
org.springframework.cache.annotation.Cacheable | результат вызова Spring-метода |
JPA second-level cache
@Entity
@jakarta.persistence.Cacheable(true)
class Country {
@Id
private String code;
private String name;
protected Country() {
// нужен JPA provider-у
}
}Аннотация только сообщает о допустимости кэширования. Нужны включённый L2 cache, выбранный provider и регион/стратегия. First-level cache принадлежит EntityManager и существует всегда; second-level разделяется между сессиями.
Кэш сущности не обязательно кэширует произвольные запросы и коллекции связей. Для Hibernate стратегия конкурентного доступа задаётся отдельно. Неподходящая стратегия или внешнее изменение БД дают устаревшие данные.
Spring Cache
@org.springframework.cache.annotation.Cacheable(
cacheNames = "countryByCode",
key = "#code",
unless = "#result == null"
)
public CountryView findCountry(String code) {
return repository.findViewByCode(code);
}Spring обычно перехватывает вызов через proxy: строит ключ, ищет значение, при промахе вызывает метод и сохраняет результат. Самовызов метода внутри того же объекта часто проходит мимо proxy. Для обновлений нужны согласованные @CachePut/@CacheEvict или другой план инвалидции.
Когда кэш вреден
- данные меняются чаще, чем читаются;
- нет допустимого времени устаревания;
- ключ не включает все влияющие аргументы, пользователя или локаль;
- в кэш попадают управляемые изменяемые entity;
- несколько узлов не согласуют инвалидцию.
На собеседовании
Включает ли JPA @Cacheable second-level cache сама? Нет, это часть конфигурации provider-а.
Совпадает ли L2 cache с кэшем запросов? Нет.
Почему Spring @Cacheable может не сработать при this.find()? Вызов не пересёк proxy.
Что сложнее записи в кэш? Корректная инвалидция и модель допустимой устарелости.
Связано: Кэширование hibernate, Spring AOP, Spring Data JPA.