📄 performance.html
字号:
<html><head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>第 20 章 提升性能 </title><link rel="stylesheet" href="../shared/css/html.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.65.1"><link rel="home" href="index.html" title="HIBERNATE - 符合Java习惯的关系数据库持久化"><link rel="up" href="index.html" title="HIBERNATE - 符合Java习惯的关系数据库持久化"><link rel="previous" href="xml.html" title="第 19 章 XML映射"><link rel="next" href="toolsetguide.html" title="第 21 章 工具箱指南"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">第 20 章 提升性能 </th></tr><tr><td width="20%" align="left"><a accesskey="p" href="xml.html">上一页</a> </td><th width="60%" align="center"> </th><td width="20%" align="right"> <a accesskey="n" href="toolsetguide.html">下一页</a></td></tr></table><hr></div><div class="chapter" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title"><a name="performance"></a>第 20 章 提升性能 </h2></div></div><div></div></div><div class="sect1" lang="zh-cn"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="performance-fetching"></a>20.1. 抓取策略(Fetching strategies) </h2></div></div><div></div></div><p> <span class="emphasis"><em>抓取策略(fetching strategy)</em></span> 是指:当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候, Hibernate如何获取关联对象的策略。抓取策略可以在O/R映射的元数据中声明,也可以在特定的HQL 或<tt class="literal">条件查询(Criteria Query)</tt>中重载声明。 </p><p> Hibernate3 定义了如下几种抓取策略: </p><div class="itemizedlist"><ul type="disc"><li><p> <span class="emphasis"><em>连接抓取(Join fetching)</em></span> - Hibernate通过 在<tt class="literal">SELECT</tt>语句使用<tt class="literal">OUTER JOIN</tt>(外连接)来 获得对象的关联实例或者关联集合。 </p></li><li><p> <span class="emphasis"><em>查询抓取(Select fetching)</em></span> - 另外发送一条 <tt class="literal">SELECT</tt> 语句抓取当前对象的关联实体或集合。除非你显式的指定<tt class="literal">lazy="false"</tt>禁止 延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。 </p></li><li><p> <span class="emphasis"><em>子查询抓取(Subselect fetching)</em></span> - 另外发送一条<tt class="literal">SELECT</tt> 语句抓取在前面查询到(或者抓取到)的所有实体对象的关联集合。除非你显式的指定<tt class="literal">lazy="false"</tt> 禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。 </p></li><li><p> <span class="emphasis"><em>批量抓取(Batch fetching)</em></span> - 对查询抓取的优化方案, 通过指定一个主键或外键列表,Hibernate使用单条<tt class="literal">SELECT</tt>语句获取一批对象实例或集合。 </p></li></ul></div><p> Hibernate会区分下列各种情况: </p><div class="itemizedlist"><ul type="disc"><li><p> <span class="emphasis"><em>Immediate fetching,立即抓取</em></span> - 当宿主被加载时,关联、集合或属性被立即抓取。 </p></li><li><p> <span class="emphasis"><em>Lazy collection fetching,延迟集合抓取</em></span>- 直到应用程序对集合进行了一次操作时,集合才被抓取。(对集合而言这是默认行为。) </p></li><li><p> <span class="emphasis"><em>Proxy fetching,代理抓取</em></span> - 对返回单值的关联而言,当其某个方法被调用,而非对其关键字进行get操作时才抓取。 </p></li><li><p> <span class="emphasis"><em>Lazy attribute fetching,属性延迟加载</em></span> - 对属性或返回单值的关联而言,当其实例变量被访问的时候进行抓取(需要运行时字节码强化)。这一方法很少是必要的。 </p></li></ul></div><p> 这里有两个正交的概念:关联<span class="emphasis"><em>何时</em></span>被抓取,以及被<span class="emphasis"><em>如何</em></span>抓取(会采用什么样的SQL语句)。不要混淆它们!我们使用<tt class="literal">抓取</tt>来改善性能。我们使用<tt class="literal">延迟</tt>来定义一些契约,对某特定类的某个脱管的实例,知道有哪些数据是可以使用的。 </p><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="performance-fetching-lazy"></a>20.1.1. 操作延迟加载的关联</h3></div></div><div></div></div><p> 默认情况下,Hibernate 3对集合使用延迟select抓取,对返回单值的关联使用延迟代理抓取。对几乎是所有的应用而言,其绝大多数的关联,这种策略都是有效的。 </p><p> <span class="emphasis"><em>注意:</em></span>假若你设置了<tt class="literal">hibernate.default_batch_fetch_size</tt>,Hibernate会对延迟加载采取批量抓取优化措施(这种优化也可能会在更细化的级别打开)。 </p><p> 然而,你必须了解延迟抓取带来的一个问题。在一个打开的Hibernate session上下文之外调用延迟集合会导致一次意外。比如: </p><pre class="programlisting">s = sessions.openSession();Transaction tx = s.beginTransaction(); User u = (User) s.createQuery("from User u where u.name=:userName") .setString("userName", userName).uniqueResult();Map permissions = u.getPermissions();tx.commit();s.close();Integer accessLevel = (Integer) permissions.get("accounts"); // Error!</pre><p> 在<tt class="literal">Session</tt>关闭后,permessions集合将是未实例化的、不再可用,因此无法正常载入其状态。 <span class="emphasis"><em>Hibernate对脱管对象不支持延迟实例化</em></span>. 这里的修改方法是:将permissions读取数据的代码 移到tx.commit()之前。 </p><p> 除此之外,通过对关联映射指定<tt class="literal">lazy="false"</tt>,我们也可以使用非延迟的集合或关联。但是, 对绝大部分集合来说,更推荐使用延迟方式抓取数据。如果在你的对象模型中定义了太多的非延迟关联,Hibernate最终几乎需要在每个事务中载入整个数据库到内存中! </p><p> 但是,另一方面,在一些特殊的事务中,我们也经常需要使用到连接抓取(它本身上就是非延迟的),以代替查询抓取。 下面我们将会很快明白如何具体的定制Hibernate中的抓取策略。在Hibernate3中,具体选择哪种抓取策略的机制是和选择 单值关联或集合关联相一致的。 </p></div><div class="sect2" lang="zh-cn"><div class="titlepage"><div><div><h3 class="title"><a name="performance-fetching-custom"></a>20.1.2. 调整抓取策略(Tuning fetch strategies) </h3></div></div><div></div></div><p> 查询抓取(默认的)在N+1查询的情况下是极其脆弱的,因此我们可能会要求在映射文档中定义使用连接抓取: </p><pre class="programlisting"><set name="permissions" fetch="join"> <key column="userId"/> <one-to-many class="Permission"/>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -