2017-01-17 2 views
0

У меня проблема с JPA в моем приложении. У меня есть родительский объект Artist с отношением one-to-one/many etch к другим объектам, которые я все настроил для ленивости. Я получаю эти сущности, используя запросы присоединения. Все это работает нормально, но иногда я получаю исключение LazyInitializationException. Я использую Stateless EJB с JPA в backend и Spring MVC на веб-уровне. Вот метод:Присоединение в JPA иногда вызывает LazyInitializationException

public Artist getArtistWithChildren(long id, boolean isFetchReviews, boolean isFetchRequests, boolean isFetchGigs, boolean isFetchVenues) { 
    StringBuilder sql = new StringBuilder(); 
    sql.append("select a from Artist a join fetch a.members mrs"); 
    if(isFetchReviews) { 
     sql.append(" left join a.reviews rvs"); 
    } if(isFetchRequests) { 
     sql.append(" left join a.requests rqs"); 
    } if(isFetchGigs) { 
     sql.append(" left join a.gigs gs"); 
    } if(isFetchVenues) { 
     sql.append(" left join a.venues vs"); 
    } 

    sql.append(" where a.id=:id"); 

    TypedQuery<Artist> query = em.createQuery(sql.toString(), Artist.class); 
    query.setParameter("id", id); 
    query.setMaxResults(1); 
    List<Artist> resultList = query.getResultList(); 
    return resultList.get(0); 
} 

А вот класс сущности Исполнитель

@Entity 
@Table(name="ARTIST") 
public class Artist extends DescribingEntity { 

private static final long serialVersionUID = -7264327449601568983L; 

@ManyToMany(mappedBy="artists", targetEntity=Member.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH}) 
private List<Member> members; 

@OneToMany(mappedBy="artist", targetEntity=VenueReview.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH, REMOVE}) 
private List<VenueReview> reviews; 

@OneToMany(mappedBy="artist", targetEntity=Gig.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH, REMOVE}) 
private List<Gig> gigs; 

@OneToMany(mappedBy="artist", targetEntity=GigRequest.class, fetch=FetchType.LAZY, cascade={MERGE, REFRESH, REMOVE}) 
private List<GigRequest> requests; 

@ManyToMany(cascade={MERGE, REFRESH}, fetch=FetchType.LAZY) 
@JoinTable(name="VENUE_ARTIST_REL", 
    [email protected](name="ARTIST_ID", referencedColumnName="ARTIST_ID"), 
    [email protected](name="VENUE_ID", referencedColumnName="VENUE_ID")) 
private List<Venue> venues; 

getters and setters... 

Я затем перейти в режим отладки, чтобы выяснить, что пошло не так, и как я пошаговый метод он не возвращает ошибки и никакое исключение не выбрасывается. Может быть, коллекция возвращается слишком рано, чтобы все данные из БД не успели правильно заполнить? Я новичок, когда речь заходит о JPA, поэтому, пожалуйста, дайте мне знать, что я сделал неправильно. Вот пример. Я использую левые соединения здесь, так как я НЕ ХОЧУ получить результаты, но мне нужна инстанцированная коллекция.

Я тестировал одно и то же, используя Arquillian, и никаких ошибок, у меня также есть аналогичные методы для других объектов, где сценарий один и тот же, просто его запуск вызывает ошибку, а пошаговая отладка - нет.

Использование Hibernate.initialize(Object o) в детских коллекциях отлично работает, но, насколько мне известно, это нехорошо делать, так как я должен сделать запрос БД для каждого ребенка (исправьте меня, если я ошибаюсь).

Я добавил Pastebin ссылки трассировки стека

Stack Trace

ответ

1

В общем, LazyInitializationException происходит, когда вы отложенную загрузку на коллекции и пытаетесь получить доступ к этой коллекции с вне сеанса, покрывающий контекст (метод по существу), в котором вы пытаетесь получить доступ к ленивой коллекции. Было бы гораздо полезнее, если вы можете оставить свой стек ошибка трассировки, чтобы получить точное решение вашей проблемы

+0

Я добавил трассировка стека как ссылка. – Johan

+1

Без сеанса, не без транзакции. Например. удаленные объекты –

+0

Мой плохой, да без сессии. Спасибо, что исправил меня. – Shriram

1

Вот объясните причину:

Проблема

Общая проблема в типичном (веб-приложении) это рендеринг представления после завершения основной логики действия, и поэтому сеанс Hibernate уже закрыт и транзакция базы данных завершена. Если вы получаете доступ к отдельным объектам, которые были загружены в сеанс внутри вашего JSP (или любой другой механизм рендеринга представлений), вы можете нажать на выгруженную коллекцию или прокси-сервер, который не инициализирован. Исключением является: LazyInitializationException: сеанс закрыт (или очень похожее сообщение). Конечно, этого следует ожидать, ведь вы уже закончили свою работу.

И решение проблемы Открытая сессия в формате. с весенним приложением вы можете использовать org.springframework.orm.hibernate5.support.OpenSessionInViewInterceptor или org.springframework.orm.hibernate5.support.OpenSessionInViewFilter, но вы не можете использовать оба в одном проекте.

Но для некоторого reasion, это трактуется как антипаттерн:

** Справка: **

Open Session in View

Смежные вопросы