Почему @Cacheable с ключом по toString() ломается на прокси-объектах
Spring Cache по умолчанию строит ключ из аргументов метода через SimpleKeyGenerator. Если аргумент — доменный объект без переопределённого equals()/hashCode(), а команда решила упростить и вручную задать ключ через toString() в SpEL, начинаются проблемы там, где их не ждали.
Проблема всплывает, когда аргумент — не обычный объект, а lazy-proxy Hibernate. toString() у прокси до инициализации возвращает что-то вроде идентификатора класса и хеша, а после инициализации — уже другую строку с реальными полями. Один и тот же логический объект даёт два разных ключа кэша в зависимости от того, был ли он уже подгружен из БД.
@Cacheable( value = "orders", key = "#customer.toString()" ) public Order findOrder(Customer customer) { return repository.find(customer); }
На собесе спросят: как правильно задать ключ вместо toString()? Явно указать конкретные поля через SpEL — key = "#customer.id" — или написать свой KeyGenerator, который работает с бизнес-идентификатором, а не с представлением объекта в памяти. Прокси тут вообще не должен участвовать в вычислении ключа.
Кэш с нестабильным ключом хуже отсутствия кэша: он молча создаёт дубликаты записей и никогда не отдаёт cache hit там, где должен.
Тренажёр: 600 вопросов, мок с таймером, план повторов
senior·base — что спрашивают на самом деле
В этом посте были ссылки, но мы их удалили по правилам Сетки