🧠 JPA: подводный камень с @ElementCollection и fetch = FetchType.EAGER
Сегодня покажу, почему @ElementCollection(fetch = FetchType.EAGER) — скрытая угроза производительности и неожиданного поведения.
📌 Суть проблемы
При использовании @ElementCollection с EAGER Hibernate делает отдельный SELECT на каждую коллекцию, даже при JOIN FETCH на родительскую сущность.
@Entity
class User {
@Id Long id;
@ElementCollection(fetch = FetchType.EAGER)
List<String> tags;
}
Запрос findAll() приведёт к N+1 проблеме:
1 запрос на User, потом по одному на каждый tags.
💡 Почему это больно
Даже если вы используете JOIN FETCH на User, Hibernate не может сделать JOIN на @ElementCollection. Это ограничение — Hibernate всегда грузит коллекцию отдельным запросом.
⚠️ Особенно опасно при pagination
Если вы делаете Page<User> — Hibernate сначала грузит User'ов, а затем делает N запросов на коллекции. В проде это быстро становится проблемой.
✅ Что делать
1. Делайте fetch = FetchType.LAZY (по умолчанию так и есть).
2. Если нужно подгрузить коллекцию — используйте @BatchSize:
@ElementCollection
@BatchSize(size = 20)
List<String> tags;
Или вручную:
SELECT u FROM User u LEFT JOIN FETCH u.tags WHERE u.id IN :ids👉 Следи за @ElementCollection — он не так прост, как кажется.
👉 @BookJava