在Hibernate中出现LazyInitializationException错误:无法初始化代理 - 没有会话。

14

我从我的服务中调用dao,代码如下:

@Override
@Transactional
public Product getProductById(int id) {
    return productDao.getProductById(id);
}

在dao中,我正在获取产品:

@Override
public Product getProductById(int id) {
    Product p = sessionFactory.getCurrentSession().load(Product.class, id);
    System.out.print(p);
    return p;
}
这段代码可以正常运行,但如果我更改我的dao类,则可能会出现问题。
@Override
public Product getProductById(int id) {
    return sessionFactory.getCurrentSession().load(Product.class, id);
}

我收到了org.hibernate.LazyInitializationException:无法初始化代理 - 没有Session。异常出现在视图层,我只是打印产品。我不明白为什么在dao方法中同一行返回结果会导致视图层中的异常,但如果我将其保存在引用中然后返回它,则可以正常工作。

4个回答

10
这个错误意味着您正在尝试访问一个延迟加载的属性或集合,但是 Hibernate 会话已关闭或不可用。Hibernate 中的“延迟加载”意味着直到在代码中访问该属性/集合时对象才会被填充(通过数据库查询)。
Hibernate 通过创建一个动态代理对象来实现这一点,该对象仅在首次使用该对象时访问数据库。为使此功能正常工作,您的对象必须在其生命周期内附加到打开的 Hibernate 会话中。
如果您删除SOP语句,则根本不会访问该对象,因此不会加载它。当您尝试在代码的其他部分访问它时,它将抛出LazyInitializationException异常。

1
SOP语句是什么? - Vishal Sharma
System.out.println - Vivek Goel

10

这是一个很好的参考资料,可以让您熟悉.get()和.load()方法的工作方式。

@Override
public Product getProductById(int id) {
    Product p = sessionFactory.getCurrentSession().load(Product.class, id);
    return p;
}

session.load()默认返回一个代理对象而不会访问数据库。如果表中没有任何记录,它基本上会返回NoObjectFoundError;否则它将返回一个引用但不填充实际对象甚至不连接到数据库。 你上面的方法返回一个代理对象,由于它还必须初始化你的对象,所以该会话保持打开状态并填充对象。

@Override
public Product getProductById(int id) {
    return sessionFactory.getCurrentSession().load(Product.class, id);
}

但在你的第二种方法中,基本上是返回一个没有任何初始化的代理(proxy)。之后会关闭此会话(session),而在此之前没有进行任何使用。因此你会得到错误信息。

希望这有所帮助。


1
这是在处理Hibernate和视图层时常见的问题。错误发生的原因是在视图渲染之前,Hibernate会话已关闭。解决这个问题的两种最简单的方法是使用Open Session In View模式或在视图渲染之前获取所有所需的数据。
由于您正在使用Spring,第一种解决方案是最简单的-只需应用OpenSessionInViewFilter(如果您使用JPA,则为OpenEntityManagerInViewFilter)。

http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/orm/hibernate4/support/OpenSessionInViewFilter.html http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/orm/jpa/support/OpenEntityManagerInViewFilter.html

你还应该阅读使用OSIV模式的利弊。

-3
在你的Product实体中,尝试在你的OneToMany关系注解中添加fetch = FetchType.EAGER,例如:
@OneToMany(mappedBy = "employee", fetch = FetchType.EAGER)
这将加载整个Product对象图,避免后续调用。

1
急切获取类型不会避免后续调用。 - Hanash Yaslem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接