JavaRush /Курси /All lectures for UA purposes /Lazy Loading при мапінгу колекцій

Lazy Loading при мапінгу колекцій

All lectures for UA purposes
Рівень 1 , Лекція 598
Відкрита

1. Параметр fetch

Розробники Hibernate давно знали про проблему, пов'язану із завантаженням дочірніх сутностей. Отже, перше, що вони зробили — додали спеціальний параметр fetch до анотацій @OneToMany, @ManyToMany.

Цей параметр може приймати два значення:

  • EAGER
  • LAZY

Приклад:

@OneToMany(fetch = FetchType.LAZY, mappedBy = "user")

Якщо параметр fetch дорівнює EAGER, то при завантаженні батьківської сутності будуть завантажені і всі її дочірні сутності. Крім того, Hibernate намагатиметься зробити це одним SQL-запитом, згенерувавши великий запит і одразу отримавши всі дані.

Якщо параметр fetch приймає значення LAZY, то при завантаженні батьківської сутності дочірня сутністьа не буде завантажен. Замість неї буде створено proxy-об'єкт.

За допомогою цього proxy-об'єкта Hibernate відстежуватиме звернення до цієї дочірньої сутності, і під час першого звернення завантажить її до пам'яті.

Якщо згадати нашу ситуацію з коментарями:


@Entity @Table(name="user")
class User {
   @Column(name="id")
   public Integer id;
 
   @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name="user_id")
   public List<Comment> comments;
}

То маєш “шикарний вибір”:

Якщо fetch = FetchType.EAGER, то Hibernate завантажить усі коментарі на першому рядку коду:


User user = session.get(User.class, 1); //завантажить всі коментарі тут
List<Comment> comments = user.getComments();

Якщо fetch = FetchType.LAZY, то Hibernate завантажить усі коментарі на другому рядку коду:


User user = session.get(User.class, 1);
List<Comment> comments = user.getComments(); //завантажить всі коментарі тут

Як ти вже здогадуєшся, варіанта, коли він не завантажить всі коментарі, у тебе немає :)

2. Значення за умовчанням

Якщо ти не вказав параметр fetch для анотації @ManyTo…, то Hibernate використовуватиме значення за замовчуванням.

Вони дещо відрізняються для різних типів анотацій. Для анотацій @OneToOne та @ManyToOne це EAGER, для анотацій @OneToMany та @ManyToMany — LAZY. Запам'ятати просто: якщо ми посилаємось на один об'єкт, то він буде завантажений повністю. Якщо посилаємось на колекцію, вона буде завантажена під час першого звернення до неї.

3. Анотація @LazyCollection

Як ти вже переконався, параметр fetch не дуже допомагає під час роботи з колекціями. Творці Hibernate спробували це виправити, за допомогою додавання спеціальної анотації @LazyCollection. Пишеться вона зазвичай так:

@LazyCollection(LazyCollectionOption.TRUE)

Вказувати її потрібно під час мапінгу полів-колекцій:


@Entity @Table(name="user")
class User {
   @Column(name="id")
   public Integer id;
 
   @OneToMany(cascade = CascadeType.ALL)
   @LazyCollection(LazyCollectionOption.TRUE)
   public List<Comment> comments;
}

Ця анотація має параметр value, який може набувати одного з трьох значень:

  • LazyCollectionOption.TRUE
  • LazyCollectionOption.FALSE
  • LazyCollectionOption.EXTRA

Перші два варіанти дуже схожі на параметр fetch.

Якщо параметр встановлено в LazyCollectionOption.TRUE, це означає, що значення поля comments не будуть завантажені з бази в момент завантаження батьківського об'єкта User. Об'єкти типу Comment будуть завантажені під час першого звернення до поля comments. Фактично це еквівалент параметра FetchType.LAZY

Якщо параметр встановлений у LazyCollectionOption.FALSE, це означає, що значення поля comments будуть завантажені з бази в момент завантаження батьківського об'єкта User. Об'єкти типу Comment будуть завантажені під час першого звернення до поля comments. Фактично це еквівалент параметра FetchType.EAGER.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ