2.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 загрузит все комментарии на 1-й строке кода:
User user = session.get(User.class, 1); //загрузит все комментарии тут
List<Comment> comments = user.getComments();
Если fetch = FetchType.LAZY
, то Hibernate загрузит все комментарии на 2-й строке кода:
User user = session.get(User.class, 1);
List<Comment> comments = user.getComments(); //загрузит все комментарии тут
Как ты уже догадываешься, варианта, когда он не загрузит все комментарии у тебя нет :)
2.2 Значение по умолчанию
Если ты не указал параметр fetch для аннотации @ManyTo
…, то Hibernate будет использовать значения по умолчанию.
Они немного отличаются для различных типов аннотаций. Для аннотаций @OneToOne
и @ManyToOne
– это EAGER, для аннотаций @OneToMany
и @ManyToMany
– это LAZY. Запомнить просто – если мы ссылаемся на один объект, то он будет загружен полностью. Если ссылаемся на коллекцию, то она будет загружена при первом обращении к ней.
2.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
.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ