📄 performance.html
字号:
</p><p> 类/实体级别的批量抓取很容易理解。假设你在运行时将需要面对下面的问题:你在一个<tt class="literal">Session</tt>中载入了25个 <tt class="literal">Cat</tt>实例,每个<tt class="literal">Cat</tt>实例都拥有一个引用成员<tt class="literal">owner</tt>, 其指向<tt class="literal">Person</tt>,而<tt class="literal">Person</tt>类是代理,同时<tt class="literal">lazy="true"</tt>。 如果你必须遍历整个cats集合,对每个元素调用<tt class="literal">getOwner()</tt>方法,Hibernate将会默认的执行25次<tt class="literal">SELECT</tt>查询, 得到其owner的代理对象。这时,你可以通过在映射文件的<tt class="literal">Person</tt>属性,显式声明<tt class="literal">batch-size</tt>,改变其行为: </p><pre class="programlisting"><class name="Person" batch-size="10">...</class></pre><p> 随之,Hibernate将只需要执行三次查询,分别为10、10、 5。 </p><p> 你也可以在集合级别定义批量抓取。例如,如果每个<tt class="literal">Person</tt>都拥有一个延迟载入的<tt class="literal">Cats</tt>集合, 现在,<tt class="literal">Sesssion</tt>中载入了10个person对象,遍历person集合将会引起10次<tt class="literal">SELECT</tt>查询, 每次查询都会调用<tt class="literal">getCats()</tt>方法。如果你在<tt class="literal">Person</tt>的映射定义部分,允许对<tt class="literal">cats</tt>批量抓取, 那么,Hibernate将可以预先抓取整个集合。请看例子: </p><pre class="programlisting"><class name="Person"> <set name="cats" batch-size="3"> ... </set></class></pre><p> 如果整个的<tt class="literal">batch-size</tt>是3(笔误?),那么Hibernate将会分四次执行<tt class="literal">SELECT</tt>查询, 按照3、3、3、1的大小分别载入数据。这里的每次载入的数据量还具体依赖于当前<tt class="literal">Session</tt>中未实例化集合的个数。 </p><p> 如果你的模型中有嵌套的树状结构,例如典型的帐单-原料结构(bill-of-materials pattern),集合的批量抓取是非常有用的。 (尽管在更多情况下对树进行读取时,<span class="emphasis"><em>嵌套集合(nested set)</em></span>或<span class="emphasis"><em>原料路径(materialized path)</em></span>(××) 是更好的解决方法。) </p></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="performance-fetching-subselect"></a>19.1.6. 使用子查询抓取(Using subselect fetching) </h3></div></div><div></div></div><p> 假若一个延迟集合或单值代理需要抓取,Hibernate会使用一个subselect重新运行原来的查询,一次性读入所有的实例。这和批量抓取的实现方法是一样的,不会有破碎的加载。 </p></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="performance-fetching-lazyproperties"></a>19.1.7. 使用延迟属性抓取(Using lazy property fetching) </h3></div></div><div></div></div><p> Hibernate3对单独的属性支持延迟抓取,这项优化技术也被称为<span class="emphasis"><em>组抓取(fetch groups)</em></span>。 请注意,该技术更多的属于市场特性。在实际应用中,优化行读取比优化列读取更重要。但是,仅载入类的部分属性在某些特定情况下会有用,例如在原有表中拥有几百列数据、数据模型无法改动的情况下。 </p><p> 可以在映射文件中对特定的属性设置<tt class="literal">lazy</tt>,定义该属性为延迟载入。 </p><pre class="programlisting"><class name="Document"> <id name="id"> <generator class="native"/> </id> <property name="name" not-null="true" length="50"/> <property name="summary" not-null="true" length="200" lazy="true"/> <property name="text" not-null="true" length="2000" lazy="true"/></class></pre><p> 属性的延迟载入要求在其代码构建时加入二进制指示指令(bytecode instrumentation),如果你的持久类代码中未含有这些指令, Hibernate将会忽略这些属性的延迟设置,仍然将其直接载入。 </p><p> 你可以在Ant的Task中,进行如下定义,对持久类代码加入“二进制指令。” </p><pre class="programlisting"><target name="instrument" depends="compile"> <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask"> <classpath path="${jar.path}"/> <classpath path="${classes.dir}"/> <classpath refid="lib.class.path"/> </taskdef> <instrument verbose="true"> <fileset dir="${testclasses.dir}/org/hibernate/auction/model"> <include name="*.class"/> </fileset> </instrument></target></pre><p> 还有一种可以优化的方法,它使用HQL或条件查询的投影(projection)特性,可以避免读取非必要的列, 这一点至少对只读事务是非常有用的。它无需在代码构建时“二进制指令”处理,因此是一个更加值得选择的解决方法。 </p><p> 有时你需要在HQL中通过<tt class="literal">抓取所有属性</tt>,强行抓取所有内容。 </p></div></div><div class="sect1" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="performance-cache"></a>19.2. 二级缓存(The Second Level Cache) </h2></div></div><div></div></div><p> Hibernate的<tt class="literal">Session</tt>在事务级别进行持久化数据的缓存操作。 当然,也有可能分别为每个类(或集合),配置集群、或JVM级别(<tt class="literal">SessionFactory级别</tt>)的缓存。 你甚至可以为之插入一个集群的缓存。注意,缓存永远不知道其他应用程序对持久化仓库(数据库)可能进行的修改 (即使可以将缓存数据设定为定期失效)。 </p><p> 默认情况下,Hibernate使用EHCache进行JVM级别的缓存(目前,Hibernate已经废弃了对JCS的支持,未来版本中将会去掉它)。 你可以通过设置<tt class="literal">hibernate.cache.provider_class</tt>属性,指定其他的缓存策略, 该缓存策略必须实现<tt class="literal">org.hibernate.cache.CacheProvider</tt>接口。 </p><div class="table"><a name="cacheproviders"></a><p class="title"><b>表 19.1. 缓存策略提供商(Cache Providers) </b></p><table summary="
 缓存策略提供商(Cache Providers)
 " border="1"><colgroup><col align="left"><col align="left"><col align="left"><col align="left"><col align="left"></colgroup><thead><tr><th align="left">Cache</th><th align="left">Provider class</th><th align="left">Type</th><th align="left">Cluster Safe</th><th align="left">Query Cache Supported</th></tr></thead><tbody><tr><td align="left">Hashtable (not intended for production use)</td><td align="left"><tt class="literal">org.hibernate.cache.HashtableCacheProvider</tt></td><td align="left">memory</td><td align="left"> </td><td align="left">yes</td></tr><tr><td align="left">EHCache</td><td align="left"><tt class="literal">org.hibernate.cache.EhCacheProvider</tt></td><td align="left">memory, disk</td><td align="left"> </td><td align="left">yes</td></tr><tr><td align="left">OSCache</td><td align="left"><tt class="literal">org.hibernate.cache.OSCacheProvider</tt></td><td align="left">memory, disk</td><td align="left"> </td><td align="left">yes</td></tr><tr><td align="left">SwarmCache</td><td align="left"><tt class="literal">org.hibernate.cache.SwarmCacheProvider</tt></td><td align="left">clustered (ip multicast)</td><td align="left">yes (clustered invalidation)</td><td align="left"> </td></tr><tr><td align="left">JBoss TreeCache</td><td align="left"><tt class="literal">org.hibernate.cache.TreeCacheProvider</tt></td><td align="left">clustered (ip multicast), transactional</td><td align="left">yes (replication)</td><td align="left">yes (clock sync req.)</td></tr></tbody></table></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="performance-cache-mapping"></a>19.2.1. 缓存映射(Cache mappings)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -