Ответ
Жадная загрузка (Eager Loading) — это стратегия загрузки связанных сущностей в Hibernate, при которой данные загружаются немедленно и вместе с родительской сущностью в рамках одного запроса к базе данных (или с помощью JOIN). Это поведение по умолчанию для коллекций, аннотированных @ElementCollection, и для связей @ManyToOne и @OneToOne.
Как работает:
При загрузке сущности Hibernate также загружает все её связи, помеченные как FetchType.EAGER, используя JOIN-запрос или дополнительные SELECT-запросы.
Пример:
@Entity
public class Author {
@Id
@GeneratedValue
private Long id;
private String name;
// ЖАДНАЯ загрузка (по умолчанию для @OneToMany)
@OneToMany(fetch = FetchType.EAGER, mappedBy = "author")
private List<Book> books = new ArrayList<>();
// Геттеры и сеттеры
}
@Entity
public class Book {
@Id
@GeneratedValue
private Long id;
private String title;
@ManyToOne(fetch = FetchType.EAGER) // ЖАДНАЯ загрузка (по умолчанию)
private Author author;
// Геттеры и сеттеры
}
Что происходит при запросе:
// Hibernate выполнит запрос с JOIN (или несколько запросов), чтобы сразу получить Author и все его Books
Author author = entityManager.find(Author.class, 1L);
// Коллекция books уже загружена в память и доступна
List<Book> authorBooks = author.getBooks();
| Плюсы и минусы: | Плюсы | Минусы |
|---|---|---|
| Связанные данные доступны сразу, нет задержек (N+1 проблемы на этом уровне). | Производительность: Загрузка большого объема ненужных данных, если связи не используются. | |
Проще в понимании (меньше ленивых исключений LazyInitializationException). |
Потребление памяти: Все загруженные объекты хранятся в контексте persistence. | |
| Риск Cartesian Product: При множественных EAGER-связях один запрос может вернуть огромное количество дублирующихся строк. |
Рекомендация: Используйте жадную загрузку только для связей, которые нужны практически всегда. В большинстве случаев предпочтительна ленивая загрузка (FetchType.LAZY) с последующей явной загрузкой через JOIN FETCH в JPQL или @EntityGraph при необходимости.
Ответ 18+ 🔞
Э, слушай, смотри, вот эта вся хуйня с жадной загрузкой в Hibernate. Представь, ты заходишь в магазин за хлебом, а тебе продавец, такой ебаный максималист, сразу впихивает в руки и хлеб, и батон, и булку, и ещё мешок муки нахуй, потому что «а вдруг пригодится». Вот это и есть Eager Loading, ёпта.
По умолчанию, эта падла Hibernate так и делает для некоторых связей — @OneToMany, например. Ты просишь одного автора, а он тебе в нагрузку сразу всех его книг притаскивает, одним махом. JOIN'ом или кучей SELECT'ов, но сразу, блядь, всё.
Смотри, как это выглядит в коде, тут всё чётко:
@Entity
public class Author {
@Id
@GeneratedValue
private Long id;
private String name;
// Вот этот самый ебучий жадный флаг. FetchType.EAGER. Он тут по дефолту.
@OneToMany(fetch = FetchType.EAGER, mappedBy = "author")
private List<Book> books = new ArrayList<>();
// Геттеры и сеттеры
}
И что потом происходит? А вот что:
// Ты думаешь: "Найди мне автора с id=1"
Author author = entityManager.find(Author.class, 1L);
// А Hibernate уже про себя думает: "Ага, автор... Ну нахуй, давай-ка я ему и все книги этого долбоёба тоже прицеплю!"
// И бабахает запрос с JOIN. И книги уже тут, в памяти.
List<Book> authorBooks = author.getBooks(); // Всё готово, бери и пользуйся, небось.
Ну и что мы имеем в сухом остатке? Плюсы и минусы, блядь.
| Что хорошего (типа плюсы) | Что пиздецового (минусы, их больше) |
|---|---|
Данные под рукой сразу. Не будешь потом, как лох, ловить LazyInitializationException где-нибудь в JSP. |
Производительность ебнулась. Загрузил кучу данных, которые, может, вообще не нужны. Зачем мне 100500 книг автора, если я только имя его посмотреть хотел? |
| Проще для понимания, особенно если мозги на ленивую загрузку не заточены. | Память жрёт, как не в себя. Все эти объекты в persistence context висят, как груз. |
| Риск получить декартово произведение, ёб твою мать! Если у сущности несколько EAGER-связей, запрос может превратиться в адскую телегу с триллионом строк, все поля повторятся до охуения. |
Так что, вывод, блядь, простой: используй эту жадность только тогда, когда связь действительно, блядь, практически всегда нужна. А так — ставь везде FetchType.LAZY, а если понадобится — явно дохуячивай данные через JOIN FETCH в JPQL или через @EntityGraph. Не будь, как тот Герасим из рассказа, который сразу всё решил радикально, а потом совесть ебала.