📄 performance.html
字号:
</p><pre class="programlisting"><class name="CatImpl" proxy="Cat"> ...... <subclass name="DomesticCatImpl" proxy="DomesticCat"> ..... </subclass></class></pre><p> 这里<tt class="literal">CatImpl</tt>实现了<tt class="literal">Cat</tt>接口, <tt class="literal">DomesticCatImpl</tt>实现<tt class="literal">DomesticCat</tt>接口。 在<tt class="literal">load()</tt>、<tt class="literal">iterate()</tt>方法中就会返回 <tt class="literal">Cat</tt>和<tt class="literal">DomesticCat</tt>的代理对象。 (注意<tt class="literal">list()</tt>并不会返回代理对象。) </p><pre class="programlisting">Cat cat = (Cat) session.load(CatImpl.class, catid);Iterator iter = session.iterate("from CatImpl as cat where cat.name='fritz'");Cat fritz = (Cat) iter.next();</pre><p> 这里,对象之间的关系也将被延迟载入。这就意味着,你应该将属性声明为<tt class="literal">Cat</tt>,而不是<tt class="literal">CatImpl</tt>。 </p><p> 但是,在有些方法中是<span class="emphasis"><em>不需要</em></span>使用代理的。例如: </p><div class="itemizedlist"><ul type="disc" compact><li><p> <tt class="literal">equals()</tt>方法,如果持久类没有重载<tt class="literal">equals()</tt>方法。 </p></li><li><p> <tt class="literal">hashCode()</tt>方法,如果持久类没有重载<tt class="literal">hashCode()</tt>方法。 </p></li><li><p> 标志符的getter方法。 </p></li></ul></div><p> Hibernate将会识别出那些重载了<tt class="literal">equals()</tt>、或<tt class="literal">hashCode()</tt>方法的持久化类。 </p><p> 若选择<tt class="literal">lazy="no-proxy"</tt>而非默认的<tt class="literal">lazy="proxy"</tt>,我们可以避免类型转换带来的问题。然而,这样我们就需要编译期字节码增强,并且所有的操作都会导致立刻进行代理初始化。 </p></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="performance-fetching-initialization"></a>19.1.4. 实例化集合和代理(Initializing collections and proxies) </h3></div></div><div></div></div><p> 在<tt class="literal">Session</tt>范围之外访问未初始化的集合或代理,Hibernate将会抛出<tt class="literal">LazyInitializationException</tt>异常。 也就是说,在分离状态下,访问一个实体所拥有的集合,或者访问其指向代理的属性时,会引发此异常。 </p><p> 有时候我们需要保证某个代理或者集合在Session关闭前就已经被初始化了。 当然,我们可以通过强行调用<tt class="literal">cat.getSex()</tt>或者<tt class="literal">cat.getKittens().size()</tt>之类的方法来确保这一点。 但是这样的程序会造成读者的疑惑,也不符合通常的代码规范。 </p><p> 静态方法<tt class="literal">Hibernate.initialized()</tt> 为你的应用程序提供了一个便捷的途径来延迟加载集合或代理。 只要它的Session处于open状态,<tt class="literal">Hibernate.initialize(cat)</tt> 将会为cat强制对代理实例化。 同样,<tt class="literal">Hibernate.initialize( cat.getKittens() )</tt> 对kittens的集合具有同样的功能。 </p><p> 还有另外一种选择,就是保持<tt class="literal">Session</tt>一直处于open状态,直到所有需要的集合或代理都被载入。 在某些应用架构中,特别是对于那些使用Hibernate进行数据访问的代码,以及那些在不同应用层和不同物理进程中使用Hibernate的代码。 在集合实例化时,如何保证<tt class="literal">Session</tt>处于open状态经常会是一个问题。有两种方法可以解决此问题: </p><div class="itemizedlist"><ul type="disc"><li><p> 在一个基于Web的应用中,可以利用servlet过滤器(filter),在用户请求(request)结束、页面生成 结束时关闭<tt class="literal">Session</tt>(这里使用了<span class="emphasis"><em>在展示层保持打开Session模式(Open Session in View)</em></span>), 当然,这将依赖于应用框架中异常需要被正确的处理。在返回界面给用户之前,乃至在生成界面过程中发生异常的情况下, 正确关闭<tt class="literal">Session</tt>和结束事务将是非常重要的, 请参见Hibernate wiki上的"Open Session in View"模式,你可以找到示例。 </p></li><li><p> 在一个拥有单独业务层的应用中,业务层必须在返回之前,为web层“准备”好其所需的数据集合。这就意味着 业务层应该载入所有表现层/web层所需的数据,并将这些已实例化完毕的数据返回。通常,应用程序应该 为web层所需的每个集合调用<tt class="literal">Hibernate.initialize()</tt>(这个调用必须发生咱session关闭之前); 或者使用带有<tt class="literal">FETCH</tt>从句,或<tt class="literal">FetchMode.JOIN</tt>的Hibernate查询, 事先取得所有的数据集合。如果你在应用中使用了<span class="emphasis"><em>Command</em></span>模式,代替<span class="emphasis"><em>Session Facade</em></span> , 那么这项任务将会变得简单的多。 </p></li><li><p> 你也可以通过<tt class="literal">merge()</tt>或<tt class="literal">lock()</tt>方法,在访问未实例化的集合(或代理)之前, 为先前载入的对象绑定一个新的<tt class="literal">Session</tt>。 显然,Hibernate将不会,也不<span class="emphasis"><em>应该</em></span>自动完成这些任务,因为这将引入一个特殊的事务语义。 </p></li></ul></div><p> 有时候,你并不需要完全实例化整个大的集合,仅需要了解它的部分信息(例如其大小)、或者集合的部分内容。 </p><p> 你可以使用集合过滤器得到其集合的大小,而不必实例化整个集合: </p><pre class="programlisting">( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()</pre><p> 这里的<tt class="literal">createFilter()</tt>方法也可以被用来有效的抓取集合的部分内容,而无需实例化整个集合: </p><pre class="programlisting">s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();</pre></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="performance-fetching-batch"></a>19.1.5. 使用批量抓取(Using batch fetching) </h3></div></div><div></div></div><p> Hibernate可以充分有效的使用批量抓取,也就是说,如果仅一个访问代理(或集合),那么Hibernate将不载入其他未实例化的代理。 批量抓取是延迟查询抓取的优化方案,你可以在两种批量抓取方案之间进行选择:在类级别和集合级别。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -