Exception in thread «main» org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role:
Exception in thread «main» org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: — эта ошибка может происходить при доступе к связанной таблице при использовании Hibernate, JPA +Hibernate и т.п.
При попытке доступа к ассоциации в другой таблице, например при использовании аннотации @OneToMany или ManyToOne, по умолчанию Hibernate будет выбирать ассоциацию отложенным (ленивым) образом, т.е. соединение для наполнения записями из связанной таблицы осуществляться не будет. Это связано с производительностью — если каждый раз вытягивать все данные из всех связанных таблиц, то можно очень сильно потерять в скорости.
Для того чтобы инфраструктура Hibernate извлекала данные из ассоциаций, можно воспользоваться одним из двух способов. При первом способе ассоциация определяется с режимом выборки EAGER. Ниже показан пример аннотации: @ManyToMany(fetch=FetchType.EAGER)
Это сообщает Hibernate о необходимости выборки связанных данных в каждом запросе. Однако, как уже упоминалось, такой подход оказывает влияние на производительность извлечения данных.
Второй способ предполагает обеспечение выборки связанных данных в запросе только по требованию. Если используется запрос Criteria, можно вызвать метод Criteria.setFetchMode() и заставить Hibernate незамедлительно выполнить выборку ассоциации. В случае применения NamedQuery для инструктирования Hibernate о необходимости незамедлительной выборки ассоциации можно использовать операцию
fetch.
Пример использования в коде (взято из JPA – пример приложения Hello World):
Первая сущность имеющая отношение один ко многим
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
@Entity @Table(name = "contact", schema = "", catalog = "javastudy") @NamedQueries({ @NamedQuery(name = "ContactEntity.findById", query = "select distinct c from ContactEntity c left join fetch c.contactTelDetails t left join fetch c.hobbies h where c.id = :id") }) public class ContactEntity { //остальной код не показан private Set<ContactTelDetailEntity> contactTelDetails = new HashSet<ContactTelDetailEntity>(); @OneToMany(mappedBy = "contact", cascade = CascadeType.ALL, orphanRemoval = true,fetch = FetchType.EAGER) public Set<ContactTelDetailEntity> getContactTelDetails() { return contactTelDetails; } public void setContactTelDetails(Set<ContactTelDetailEntity> contactTelDetails) { this.contactTelDetails = contactTelDetails; } } |
Связанная сущность:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
@Entity @Table(name = "contact_tel_detail", schema = "", catalog = "javastudy") public class ContactTelDetailEntity { //остальной код не показан @ManyToOne @JoinColumn(name = "contact_id") public ContactEntity getContact() { return contact; } public void setContact(ContactEntity contact) { this.contact = contact; } } |
В первом классе используется оба описанных способа — как указание left join fetch в именованном запросе, т.к. и в аннотации fetch = FetchType.EAGER.
5