toString() у сущности с ленивой коллекцией — рабочий код до первого лога

Lombok @Data или сгенерированный IDE toString() включает все поля класса — в том числе @OneToMany и @ManyToMany коллекции. На тестах с одной записью в базе это незаметно.

Как только сущность попадает в log.debug() или log.info() с плейсхолдером, toString() вызывается для построения строки. Если коллекция ленивая и сессия уже закрыта — LazyInitializationException. Если сессия открыта — Hibernate тихо подтягивает всю коллекцию отдельным запросом, просто чтобы её распечатать.

Хуже: это происходит на каждый вызов лога, даже если уровень DEBUG выключен в проде — если код собирает строку конкатенацией, а не через плейсхолдер SLF4J.

@Entity @Data public class Order {

@OneToMany(mappedBy = "order") private List items; }

// где-то в сервисе log.debug("Processing order: {}", order); // toString() трогает items, // коллекция лениво инициализируется

Следом спросят, как чинить. Вариант первый — исключить ленивые поля из toString() через @ToString.Exclude у Lombok. Вариант второй — не логировать сущность напрямую, а отдельные поля или DTO. Третий, менее очевидный — помнить, что даже с плейсхолдером SLF4J аргумент вычисляется всегда, независимо от уровня логирования, если это не метод с проверкой isDebugEnabled().

toString() у сущности — это не print, а потенциальный запрос к базе, спрятанный за самой безобидной строчкой лога.

Тренажёр: 600 вопросов, мок с таймером, план повторов

senior·base — что спрашивают на самом деле


В этом посте были ссылки, но мы их удалили по правилам Сетки