12

Foo 看起来有这个:

@ManyToMany
private Set<User> favouritedBy;

而用户有这个:

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

并且 fooService 有这个,在会话打开时通过事务方法访问延迟加载的集合:

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

4 回答 4

13

FetchTypea中的默认值ManyToMany使用惰性关联LAZY的休眠文档清楚地将这种访问称为错误。只有在会话仍处于打开状态时,您才能与延迟关联的对象进行交互。该部分文档还提供了访问对象的此类惰性关联成员的替代方法。我们更喜欢按照我们的应用程序中使用的标准指定获取模式JOIN

编辑

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

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

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

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

于 2012-12-02T16:27:51.773 回答
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>
    

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

于 2014-12-04T04:14:52.233 回答
2

是的,应该在事务上下文中访问该对象,否则该操作将抛出一个LazyInitializationException.

于 2013-11-21T17:01:46.473 回答
0

如果您使用任何 @...Many... 关系以及 Fetch 类型“Lazy”并且您得到 LazyInitializationException - 这意味着您关闭了 OpenInView,这很好。

为了避免LazyInitializationException转向 OIV(这使得 Hibernate 会话打开的时间比大多数情况下需要的时间长) - 确保您在发布列上指定了 @Fetch(FetchMode.JOIN)。

示例:之前:

@ManyToMany(fetch = FetchType.LAZY)
private Set<Kek> keks;

后:

@Fetch(FetchMode.JOIN)
@ManyToMany(fetch = FetchType.LAZY)
private Set<Kek> keks;

这样,您将强制使用 Join Fetch 类型,该类型将(非常简单地说)提供正确的查询以及所需的链接实体 Joined,而不是强迫您使用 Eager fetch。

于 2020-11-29T13:41:27.010 回答