Код реализует cache-aside: сначала читает кэш, при промахе — БД и сохраняет найденный заказ. Основные риски — устаревшие данные, одновременные промахи и неоговорённое поведение при сбое кэша.
package ru.tbank;
Код реализует cache-aside: сначала читает кэш, при промахе — БД и сохраняет найденный заказ. Основные риски — устаревшие данные, одновременные промахи и неоговорённое поведение при сбое кэша.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
package ru.tbank;
@Service public class OrderService { @Autowired private OrderRepository orderRepository; @Autowired private CacheService cacheService;
public Order findOrder(Long orderId) {
Order order = cacheService.get(orderId);
if (order == null) {
order = orderRepository.findById(orderId).orElse(null);
if (order != null) {
cacheService.put(orderId, order);
}
}
return order;
}
}
Ответ
Код реализует cache-aside: сначала читает кэш, при промахе — БД и сохраняет найденный заказ. Основные риски — устаревшие данные, одновременные промахи и неоговорённое поведение при сбое кэша.
Зависимости лучше передавать конструктором. Для записи в кэш нужны TTL и стратегия инвалидации при изменении заказа; TTL сам по себе не обеспечивает строгую актуальность. Отсутствующий заказ сейчас не кэшируется, поэтому частые запросы несуществующего ID нагружают БД. При конкурентных промахах возможен stampede: помогают объединение запросов на ключ и ограниченное ожидание. Нельзя кэшировать ошибки как «не найдено». Nullable-результат либо Optional выбирают явно по контракту метода.