🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 19.1.4\. 实例化集合和代理(Initializing collections and proxies) 在`Session`范围之外访问未初始化的集合或代理,Hibernate将会抛出`LazyInitializationException`异常。 也就是说,在分离状态下,访问一个实体所拥有的集合,或者访问其指向代理的属性时,会引发此异常。 有时候我们需要保证某个代理或者集合在Session关闭前就已经被初始化了。 当然,我们可以通过强行调用`cat.getSex()`或者`cat.getKittens().size()`之类的方法来确保这一点。 但是这样的程序会造成读者的疑惑,也不符合通常的代码规范。 静态方法`Hibernate.initialized()` 为你的应用程序提供了一个便捷的途径来延迟加载集合或代理。 只要它的Session处于open状态,`Hibernate.initialize(cat)` 将会为cat强制对代理实例化。 同样,`Hibernate.initialize( cat.getKittens() )` 对kittens的集合具有同样的功能。 还有另外一种选择,就是保持`Session`一直处于open状态,直到所有需要的集合或代理都被载入。 在某些应用架构中,特别是对于那些使用Hibernate进行数据访问的代码,以及那些在不同应用层和不同物理进程中使用Hibernate的代码。 在集合实例化时,如何保证`Session`处于open状态经常会是一个问题。有两种方法可以解决此问题: * 在一个基于Web的应用中,可以利用servlet过滤器(filter),在用户请求(request)结束、页面生成 结束时关闭`Session`(这里使用了_在展示层保持打开Session模式(Open Session in View)_), 当然,这将依赖于应用框架中异常需要被正确的处理。在返回界面给用户之前,乃至在生成界面过程中发生异常的情况下, 正确关闭`Session`和结束事务将是非常重要的, 请参见Hibernate wiki上的"Open Session in View"模式,你可以找到示例。 * 在一个拥有单独业务层的应用中,业务层必须在返回之前,为web层“准备”好其所需的数据集合。这就意味着 业务层应该载入所有表现层/web层所需的数据,并将这些已实例化完毕的数据返回。通常,应用程序应该 为web层所需的每个集合调用`Hibernate.initialize()`(这个调用必须发生咱session关闭之前); 或者使用带有`FETCH`从句,或`FetchMode.JOIN`的Hibernate查询, 事先取得所有的数据集合。如果你在应用中使用了_Command_模式,代替_Session Facade_ , 那么这项任务将会变得简单的多。 * 你也可以通过`merge()`或`lock()`方法,在访问未实例化的集合(或代理)之前, 为先前载入的对象绑定一个新的`Session`。 显然,Hibernate将不会,也不_应该_自动完成这些任务,因为这将引入一个特殊的事务语义。 有时候,你并不需要完全实例化整个大的集合,仅需要了解它的部分信息(例如其大小)、或者集合的部分内容。 你可以使用集合过滤器得到其集合的大小,而不必实例化整个集合: ``` ( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue() ``` 这里的`createFilter()`方法也可以被用来有效的抓取集合的部分内容,而无需实例化整个集合: ``` s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list(); ```