一尘不染

org.hibernate.LazyInitializationException:无法初始化代理-没有会话,请再次确认

hibernate

Foo看起来里面有这个:

@ManyToMany
private Set<User> favouritedBy;

当用户拥有此功能时:

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

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;
}

编辑 无需使用标准即可解决此问题:

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();

阅读 200

收藏
2020-06-20

共1个答案

一尘不染

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

编辑

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

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

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

为了解决这个问题,您应该使用Criteria对象检索用户并指定提取类型,JOIN以便在返回的User对象中填充Foo对象。

2020-06-20