📄 best-practices.html
字号:
</p></dd><dt><span class="term">在性能瓶颈的地方使用硬编码的JDBC</span></dt><dd><p> 在对性能要求很严格的一些系统中,一些操作(例如批量更新和批量删除)也许直接使用JDBC会更好,但是请先<span class="emphasis"><em>搞清楚</em></span>这是否是一个瓶颈,并且不要想当然认为JDBC一定会更快。如果确实需要直接使用JDBC,那么最好打开一个Hibernate <tt class="literal">Session</tt> 然后从 <tt class="literal">Session</tt>获得connection,按照这种办法你仍然可以使用同样的transaction策略和底层的connection provider。 </p></dd><dt><span class="term">理解<tt class="literal">Session</tt>清洗( flushing)</span></dt><dd><p> Session会不时的向数据库同步持久化状态,如果这种操作进行的过于频繁,性能会受到一定的影响。有时候你可以通过禁止自动flushing,尽量最小化非必要的flushing操作,或者更进一步,在一个特定的transaction中改变查询和其它操作的顺序。 </p></dd><dt><span class="term">在三层结构中,考虑使用 <tt class="literal">saveOrUpdate()</tt></span></dt><dd><p> 当使用一个servlet / session bean 类型的架构的时候, 你可以把已加载的持久对象在session bean层和servlet / JSP 层之间来回传递。使用新的session来为每个请求服务,使用 <tt class="literal">Session.update()</tt> 或者<tt class="literal">Session.saveOrUpdate()</tt>来更新对象的持久状态。 </p></dd><dt><span class="term">在两层结构中,考虑断开session.</span></dt><dd><p> 为了得到最佳的可伸缩性,数据库事务(Database Transaction)应该尽可能的短。但是,程序常常需要实现长时间运行的“应用程序事务(Application Transaction)”,包含一个从用户的观点来看的原子操作。这个应用程序事务可能跨越多次从用户请求到得到反馈的循环。请使用脱管对象(与session脱离的对象),或者在两层结构中,把Hibernate Session从JDBC连接中脱离开,下次需要用的时候再连接上。绝不要把一个Session用在多个应用程序事务(Application Transaction)中,否则你的数据可能会过期失效。 </p></dd><dt><span class="term">不要把异常看成可恢复的</span></dt><dd><p> 这一点甚至比“最佳实践”还要重要,这是“必备常识”。当异常发生的时候,必须要回滚 <tt class="literal">Transaction</tt> ,关闭<tt class="literal">Session</tt>。如果你不这样做的话,Hibernate无法保证内存状态精确的反应持久状态。尤其不要使用<tt class="literal">Session.load()</tt>来判断一个给定标识符的对象实例在数据库中是否存在,应该使用<tt class="literal">find()</tt>。 </p></dd><dt><span class="term">对于关联优先考虑lazy fetching </span></dt><dd><p> 谨慎的使用主动外连接抓取(eager (outer-join) fetching)。对于大多数没有JVM级别缓存的持久对象的关联,应该使用代理(proxies)或者具有延迟加载属性的集合(lazy collections)。对于被缓存的对象的关联,尤其是缓存的命中率非常高的情况下,应该使用<tt class="literal">outer-join="false"</tt>,显式的禁止掉eager fetching。如果那些特殊的确实适合使用outer-join fetch 的场合,请在查询中使用<tt class="literal">left join</tt>。 </p></dd><dt><span class="term">考虑把Hibernate代码从业务逻辑代码中抽象出来</span></dt><dd><p> 把Hibernate的数据存取代码隐藏到接口(interface)的后面,组合使用<span class="emphasis"><em>DAO</em></span>和<span class="emphasis"><em>Thread Local Session</em></span>模式。通过Hibernate的<tt class="literal">UserType</tt>,你甚至可以用硬编码的JDBC来持久化那些本该被Hibernate持久化的类。 (该建议更适用于规模足够大应用软件中,对于那些只有5张表的应用程序并不适合。) </p></dd><dt><span class="term">使用与业务有关的键值来实现<tt class="literal">equals()</tt>和 <tt class="literal">hashCode()</tt> .</span></dt><dd><p> 如果你在Session外比较对象,你必须要实现<tt class="literal">equals()</tt>和 <tt class="literal">hashCode()</tt>。在Session内部,Java的对象识别机制是可以保证的。如果你实现了这些方法,不要再使用数据库(主键)辨识!瞬时对象不具有(数据库)标识值,Hibernate会在对象被保存的时候赋予它一个值。如果对象在被保存的时候位于Set内,hash code就会变化,要约就被违背。为了实现用与业务有关的键值编写<tt class="literal">equals()</tt>和 <tt class="literal">hashCode()</tt>,你应该使用类属性的唯一组合。记住,这个键值只是当对象位于Set内部时才需要保证稳定且唯一,并不是在其整个生命周期中都需要(不需要达到数据库主键这样的稳定性)。绝不要在<tt class="literal">equals()</tt>中比较集合(要考虑延迟装载),并且小心对待其他可能被代理过的类。 </p></dd><dt><span class="term">不要用怪异的连接映射</span></dt><dd><p> 多对多连接用得好的例子实际上相当少见。大多数时候你在“连接表”中需要保存额外的信息。这种情况下,用两个指向中介类的一对多的连接比较好。实际上,我们认为绝大多数的连接是一对多和多对一的,你应该谨慎使用其它连接风格,用之前问自己一句,是否真的必须这么做。 </p></dd></dl></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="example-mappings.html">上一页</a> </td><td width="20%" align="center"><a accesskey="u" href="index.html">上一级</a></td><td width="40%" align="right"> </td></tr><tr><td width="40%" align="left" valign="top">第 24 章 示例:复杂映射实例 </td><td width="20%" align="center"><a accesskey="h" href="index.html">起始页</a></td><td width="40%" align="right" valign="top"> </td></tr></table></div></body></html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -