Org.hibernate.LazyInitializationException: не удалось инициализировать прокси-сервер - нет сеанса, на бис un fois

Foo выглядит так:

@ManyToMany
private Set<User> favouritedBy;

в то время как у пользователя есть это:

@ManyToMany(mappedBy = "favouritedBy")
private Set<Foo> favourites  = new HashSet<Foo>();
public Set<Foo> getFavourites() {
  return favourite;
}

И fooService имеет это: при доступе к lazyloaded коллекции, когда сеанс открыт, с помощью метода tranactal:

@Transactional(readOnly = true)
public Set<Foo> getFavourites(User user) {
user = dao.get(User.class, user.getId()); //the dao gets a session
Set<Foo> favourites = user.getFavourites();//but the session is not here and the exception is thrown?
return  favourties;
}

ИЗМЕНИТЬ Это исправляет его, не используя критерии:

Set<Foo> favourites = new HashSet<Foo>(user.getFavourites());

и это исправляет его с помощью критериев

Session session = sessionFactory.getCurrentSession();
final Criteria crit = session.createCriteria(Foo.class);
crit.setFetchMode("favourites", FetchMode.JOIN);
crit.add(Property.forName("id").eq(id));
return (Foo) crit.uniqueResult();

Ответ 1

По умолчанию FetchType в ManyToMany есть LAZY, а документация hibernate для работает с ленивыми ассоциациями явно вызывает такой вид доступа как ошибку. Вы можете взаимодействовать с лениво связанными объектами только в то время, когда сеанс все еще открыт. Эта часть документации также предоставляет альтернативы для доступа к таким лениво связанным элементам объекта. Мы предпочитаем указывать режим выборки как JOIN в используемых критериях, в наших приложениях

Edit

Set<Foo> favourites = user.getFavourites();

Вышеприведенный оператор фактически не возвращает набор, содержащий все объекты Foo. Это просто прокси. Фактические объекты Foo извлекаются только тогда, когда доступны элементы в наборе, такие как favorites.iterator() и т.д. Эта операция явно происходит вне вашего метода getFavorites(). Но аннотация @Transactional по методу getFavorites() указывает, что сеанс будет закрыт в конце этого метода.

Итак, когда методы вызываются в избранном наборе, сеанс уже закрыт и, следовательно, исключение.

Чтобы устранить это, вы должны использовать объект Criteria для извлечения пользователя и указать тип выборки как JOIN, чтобы объекты Foo были заполнены в возвращаемом объекте User.

Ответ 2

Существует два решения.

  • Не используйте ленивую загрузку.

    Установить lazy=false в XML или Установить @OneToMany(fetch = FetchType.EAGER) В аннотации.

  • Используйте ленивую загрузку.

    Установить lazy=true в XML или Установить @OneToMany(fetch = FetchType.LAZY) В аннотации.

    и добавьте фильтр в web.xml

     <listener>
         ...
     </listener>
     <filter>
         <filter-name>hibernateFilter</filter-name>
         <filter-class>
             org.springframework.orm.hibernate4.support.OpenSessionInViewFilter
         </filter-class>
         <init-param>
             <param-name>sessionFactoryBeanName</param-name>
             <param-value>mySessionFactory</param-value> 
         </init-param>
     </filter>
     <filter-mapping>
         <filter-name>hibernateFilter</filter-name>
         <url-pattern>/*</url-pattern>
     </filter-mapping>
     <servlet>
         ...
     </servlet>
    

И <param-value>mySessionFactory</param-value> - это имя sessionFacory bean, которое определено в applicationContext.xml

Ответ 3

Да, к объекту следует обращаться в транзакционном контексте, в противном случае операция выдаст LazyInitializationException.