← Назад к вопросам

Какая аннотация используется для работы с кэшем?

1.2 Junior🔥 141 комментариев
#Кэширование и NoSQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Аннотации для работы с кэшем в Spring

Spring предоставляет мощные аннотации для управления кэшированием. Это позволяет улучшить производительность приложения, сокращая время обработки часто используемых данных.

1. @Cacheable (Чтение из кэша)

Основная аннотация для кэширования результатов методов:

@Service
public class UserService {
    
    @Cacheable("users") // Кэшировать результат в кэше "users"
    public User getUserById(Long id) {
        // Если это вызов повторно с одним и тем же id,
        // результат вернётся из кэша, метод не выполнится
        System.out.println("Загружаю пользователя из БД: " + id);
        return userRepository.findById(id).orElse(null);
    }
    
    // С условием кэширования
    @Cacheable(value = "users", condition = "#id > 100")
    public User getCachedIfBigId(Long id) {
        return userRepository.findById(id).orElse(null);
    }
    
    // С unless (инверсия condition)
    @Cacheable(value = "users", unless = "#result == null")
    public User getUserOrNull(Long id) {
        return userRepository.findById(id).orElse(null);
    }
    
    // С кастомным ключом кэша
    @Cacheable(value = "users", key = "'user_' + #id")
    public User getUser(Long id) {
        return userRepository.findById(id).orElse(null);
    }
}

Параметры:

  • value/cacheNames — имя кэша
  • key — ключ для сохранения (SpEL выражение)
  • condition — условие кэширования
  • unless — когда НЕ кэшировать

2. @CachePut (Обновление кэша)

Всегда выполняет метод и обновляет кэш:

@Service
public class UserService {
    
    @CachePut("users") // Выполнить метод И обновить кэш
    public User updateUser(User user) {
        System.out.println("Обновляю пользователя в БД");
        return userRepository.save(user);
    }
    
    // С условием и ключом
    @CachePut(value = "users", key = "#result.id")
    public User createUser(String name, String email) {
        return userRepository.save(new User(name, email));
    }
}

Отличие от @Cacheable:

  • @Cacheable — возвращает из кэша если есть
  • @CachePut — всегда выполняет и обновляет

3. @CacheEvict (Очистка кэша)

Удаляет данные из кэша:

@Service
public class UserService {
    
    @CacheEvict("users") // Удалить из кэша
    public void deleteUser(Long id) {
        System.out.println("Удаляю пользователя");
        userRepository.deleteById(id);
    }
    
    // Удалить все из кэша
    @CacheEvict(value = "users", allEntries = true)
    public void clearAllUsers() {
        System.out.println("Очищаю весь кэш пользователей");
    }
    
    // Удалить с условием
    @CacheEvict(value = "users", condition = "#id > 1000")
    public void deleteIfBigId(Long id) {
        userRepository.deleteById(id);
    }
}

4. @Caching (Комбинированные операции)

Для сложных сценариев с несколькими операциями кэша:

@Service
public class UserService {
    
    @Caching(
        put = {
            @CachePut(value = "users", key = "#result.id"),
            @CachePut(value = "usersByEmail", key = "#result.email")
        }
    )
    public User createUser(String name, String email) {
        return userRepository.save(new User(name, email));
    }
    
    @Caching(
        evict = {
            @CacheEvict(value = "users", key = "#id"),
            @CacheEvict(value = "usersByEmail", allEntries = true)
        }
    )
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}

5. @CacheConfig (Конфигурация на уровне класса)

Задаёт дефолтный кэш для всего класса:

@Service
@CacheConfig(cacheNames = "users") // Дефолтный кэш для всех методов
public class UserService {
    
    @Cacheable // Используется "users" кэш из @CacheConfig
    public User getUserById(Long id) {
        return userRepository.findById(id).orElse(null);
    }
    
    @CacheEvict(allEntries = true) // Очищает "users" кэш
    public void refreshAll() {
    }
}

Конфигурация кэша

Способ 1: Простое включение

@Configuration
@EnableCaching // Включить поддержку кэша
public class CacheConfig {
}

В application.properties:

spring.cache.type=simple

Способ 2: Redis кэш (Production)

@Configuration
@EnableCaching
public class CacheConfig {
    @Bean
    public LettuceConnectionFactory connectionFactory() {
        return new LettuceConnectionFactory();
    }
}

Добавить зависимость:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

Конфигурация:

spring.cache.type=redis
spring.redis.host=localhost
spring.redis.port=6379

Способ 3: Caffeine кэш (In-memory)

@Configuration
@EnableCaching
public class CacheConfig {
    @Bean
    public CacheManager cacheManager() {
        return new CaffeineCacheManager("users", "posts", "comments");
    }
}

Или с настройками:

@Bean
public CacheManager cacheManager() {
    CaffeineCacheManager manager = new CaffeineCacheManager("users");
    manager.setCaffeine(Caffeine.newBuilder()
        .maximumSize(1000)
        .expireAfterWrite(10, TimeUnit.MINUTES));
    return manager;
}

Практический пример

@Service
public class UserService {
    private final UserRepository userRepository;
    
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
    
    // Получить с кэшем
    @Cacheable(value = "users", key = "#id")
    public User findById(Long id) {
        System.out.println("Запрос к БД для id: " + id);
        return userRepository.findById(id).orElse(null);
    }
    
    // Получить все (без кэша — сложно для больших объёмов)
    public List<User> findAll() {
        return userRepository.findAll();
    }
    
    // Создать и добавить в кэш
    @CachePut(value = "users", key = "#result.id")
    public User create(String name, String email) {
        System.out.println("Создание нового пользователя");
        return userRepository.save(new User(name, email));
    }
    
    // Обновить
    @CachePut(value = "users", key = "#user.id")
    public User update(User user) {
        System.out.println("Обновление пользователя: " + user.getId());
        return userRepository.save(user);
    }
    
    // Удалить
    @CacheEvict(value = "users", key = "#id")
    public void delete(Long id) {
        System.out.println("Удаление пользователя: " + id);
        userRepository.deleteById(id);
    }
}

Пример использования:

UserService service = new UserService(repo);

// Первый вызов — идёт в БД
User user1 = service.findById(1L); // "Запрос к БД для id: 1"

// Второй вызов — из кэша
User user2 = service.findById(1L); // Ничего не выводится (из кэша)

// Обновление
user1.setName("New Name");
service.update(user1); // Кэш обновлен

// Удаление
service.delete(1L); // Кэш очищен для id=1

Ключевые моменты

АннотацияДействиеКогда использовать
@CacheableВернуть из кэша если естьЧтение данных
@CachePutВсегда выполнить и обновить кэшОбновление, создание
@CacheEvictУдалить из кэшаУдаление, инвалидация
@CachingКомбинировать операцииСложные сценарии
@CacheConfigДефолтная конфигурацияУпрощение аннотаций

Best Practices

  • Кэшируйте read-only методы — чаще всего @Cacheable
  • Тщательно выбирайте ключи кэша — могут быть конфликты
  • Инвалидируйте кэш при изменениях — @CacheEvict
  • Используйте условия — не кэшируйте всё подряд
  • Redis для микросервисов — общий кэш между сервисами
  • Caffeine для монолитов — in-memory кэш, быстро
  • Мониторьте попадания в кэш — не кэшируйте впустую