org.hibernate.LazyInitializationException:无法初始化代理 - 没有Session,加入un fois

Nim*_*sky 10 java spring hibernate

Foo看起来有这个:

@ManyToMany
private Set<User> favouritedBy;
Run Code Online (Sandbox Code Playgroud)

用户有这个:

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

并且fooService具有此功能,通过tranactional方法在会话打开时访问lazyloaded集合:

@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;
}
Run Code Online (Sandbox Code Playgroud)

编辑 修复它,不使用条件:

Set<Foo> favourites = new HashSet<Foo>(user.getFavourites());
Run Code Online (Sandbox Code Playgroud)

这用标准修复了它

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();
Run Code Online (Sandbox Code Playgroud)

Vik*_*dor 10

默认FetchTypeManyToManyLAZY和Hibernate文档与懒惰协会合作明确调用这种访问是错误的.只有在会话仍处于打开状态时,您才能与延迟关联的对象进行交互.该部分文档还提供了访问对象的懒惰关联成员的替代方法.我们更喜欢JOIN在我们的应用程序中使用的标准中指定获取模式

编辑:

Set<Foo> favourites = user.getFavourites();
Run Code Online (Sandbox Code Playgroud)

上面的语句实际上并不返回包含所有Foo对象的集合.它只是一个代理.Foo仅当访问集合中的元素favorites.iterator()等时才会获取实际对象.此操作显然发生在getFavorites()方法之外.但是该方法的@Transactional注释getFavorites()表明会话将在此方法结束时关闭.

因此,当在收藏夹集上调用方法时,会话已经关闭,因此异常.

要解决此问题,您应该使用Criteria对象来检索用户并指定fetch类型,JOIN以便在返回的User对象中填充Foo对象.


小智 9

有两种解决方案.

  1. 不要使用延迟加载.

    设置lazy=false在XML或设置@OneToMany(fetch = FetchType.EAGER)在注解.

  2. 使用延迟加载.

    设置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>
    
    Run Code Online (Sandbox Code Playgroud)

并且<param-value>mySessionFactory</param-value>是您定义的sessionFacory bean名称applicationContext.xml