利用Hibernate延迟加载?

时间:2010-02-20 20:11:12

标签: java hibernate spring lazy-loading

我有一个域对象,其属性是包含另一个域对象的集合。这是使用hibernate映射(最终在另一个表上执行连接)来完成的。默认情况下,Hibernate似乎懒得实例化这个集合。事实证明这是件好事,因为根据我需要显示的内容,我并不总是需要加载这个集合。

我的问题如下:在编写我的hibernate查询时(在我的DAO中),我使用以下内容来打开/关闭会话:

Session session = getSessionFactory().openSession();
//query goes here using the session var
session.close();

问题是:当Hibernate最终懒洋洋地加载我的集合时,Session一直关闭!我怎么能绕过这个?我假设我必须像我一样关闭会议......

这是我得到的错误:

SEVERE: failed to lazily initialize a collection of ...

2 个答案:

答案 0 :(得分:5)

如果在网络应用中发生这种情况,则可以轻松解决此问题,即使用OpenSessionInViewInterceptorOpenSessionInViewFilter。这会延迟会话的关闭,直到整个请求完成,允许您在渲染视图时导航延迟关联。

更通用的解决方案是重写您的查询,以便它们明确指定应该预先获取哪些关联。这使您可以在默认情况下保持关联的延迟,同时满足您希望它们急切获取的特殊情况。请参阅Hibernate文档中的"fetch joins"说明。

  

“获取”连接允许关联或   价值集合   与父母一起初始化   使用单个选择的对象。这是   在a的情况下特别有用   采集。它有效地覆盖了   外连接和延迟声明   关联的映射文件   和收藏品

答案 1 :(得分:2)

我知道您为每个DAO操作打开和关闭会话。您可以使用所有DAO使用同一个会话,在初始化期间打开并在关闭时关闭。请注意,Hibernate Reference提到“每个操作的会话”作为反模式:

“不要使用session-per-operation反模式:不要在单个线程中为每个简单的数据库调用打开和关闭Session。”

简而言之,会话应包含工作单元。这可以是单个用户请求(可能包括多个查询),也可以是更长的会话(包括具有自己的(一组)查询的多个屏幕)。在后一种情况下,有理由考虑不让会话(=交易)在长时间的用户思考时间内保持开放,但是你的听起来并不像我这样。

如果您关闭会话,您的域对象将分离。您可以打开一个新会话,将对象绑定到它然后加载集合,但对我来说这看起来很麻烦。