﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-WOLF--执着-文章分类-HIBERNATE</title><link>http://www.blogjava.net/sutao/category/24688.html</link><description>用文字记录学习的体验！</description><language>zh-cn</language><lastBuildDate>Wed, 21 Nov 2007 01:53:31 GMT</lastBuildDate><pubDate>Wed, 21 Nov 2007 01:53:31 GMT</pubDate><ttl>60</ttl><item><title>详细讲解在Hibernate中检索策略的应用</title><link>http://www.blogjava.net/sutao/articles/161878.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Tue, 20 Nov 2007 07:59:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/161878.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/161878.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/161878.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/161878.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/161878.html</trackback:ping><description><![CDATA[<h1 id="pageName">详细讲解在Hibernate中检索策略的应用</h1>
<div class="feature">&nbsp;</div>
<div class="story">
<p>　　<a href="http://www.pcdog.com/special/1202/index.html" target="_blank">Hibernate</a>的检索<nobr oncontextmenu="return false;" onmousemove="kwM(1);" id="key1" onmouseover="kwE(event,1, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">策略</nobr>包括类级别检索策略和关联级别检索策略。</p>
<div class="ad0">　　类级别检索策略有立即检索和延迟检索，默认的检索策略是立即检索。在Hibernate映射文件中，通过在&lt;不着class&gt;上配置lazy属性来确定检索策略。对于Session的检索方式，类级别检索策略仅适用于load方法；也就说，对于get、 qurey检索，持久化对象都会被立即加载而不管lazy是false还是true.一般来说，我们检索对象就是要访问它，因此立即检索是通常的选择。由于load方法在检索不到对象时会抛出异常（立即检索的情况下），因此我个人并不建议使用load检索；而由于&lt; class&gt;中的lazy属性还影响到多对一及一对一的检索策略，因此使用load方法就更没必要了。</div>
<p>　　关联级别检索策略有立即检索、延迟检索和迫切左外连接检索。对于关联级别检索，又可分为一对多和多对多、多对一和一对一两种情况讨论。</p>
<p>　　一对多和多对多关联关系一般使用&lt; set&gt;配置。&lt; set&gt;有lazy和outer-join属性，它们的不同取值绝对了检索策略。</p>
<p>　　1）立即检索：这是一对多默认的检索策略，此时lazy=false，outer-join=false.尽管这是默认的检索策略，但如果关联的集合是无用的，那么就不要使用这种检索方式。</p>
<p>　　2）延迟检索：此时lazy=true，outer-join=false（outer-join=true是无意义的），这是优先考虑的检索方式。</p>
<p>　　3）迫切左外连接检索：此时 lazy=false，outer-join=true，这种检索策略只适用于依靠id检索方式（load、get），而不适用于query的集合检索（它会采用立即检索策略）。相比于立即检索，这种检索策略减少了一条sql语句，但在Hibernate中，只能有一个配置成 outer-join=true.</p>
<p>　　多对一和一对一检索策略一般使用&lt; many-to-one&gt;、&lt; one-to-one&gt;配置。&lt; many-to-one&gt;中需要配置的属性是 outer-join，同时还需要配置one端关联的&lt; class&gt;的lazy属性（配置的可不是&lt; many-to-one&gt;中的lazy哦），它们的组合后的检索策略如下：</p>
<p>　　1） outer-join=auto：这是默认值，如果lazy=true为延迟检索，如果lazy=false为迫切左外连接检索。</p>
<p>　　2） outer-join=true，无关于lazy，都为迫切左外连接检索。</p>
<p>　　3） outer-join=false，如果lazy=true为延迟检索，否则为立即检索。</p>
<p>　　可以看到，在默认的情况下（outer-join=auto，lazy=false），对关联的one端对象Hibernate采用的迫切左外连接检索。依我看，很多情况下，我们并不需要加载one端关联的对象（很可能我们需要的仅仅是关联对象的id）；另外，如果关联对象也采用了迫切左外连接检索，就会出现select语句中有多个外连接表，如果个数多的话会影响检索性能，这也是为什么Hibernate通过 hibernate.max_fetch_depth属性来控制外连接的深度。对于迫切左外连接检索，query的集合检索并不适用，它会采用立即检索策略。</p>
<p>　　对于检索策略，需要根据实际情况进行选择。对于立即检索和延迟检索，它们的优点在于select语句简单（每张表一条语句）、查询速度快，缺点在于关联表时需要多条select语句，增加了访问<a href="http://www.pcdog.com/special/1229/index.html" target="_blank">数据库</a>的频率。因此在选择即检索和延迟检索时，可以考虑使用批量检索策略来<nobr oncontextmenu="return false;" onmousemove="kwM(4);" id="key3" onmouseover="kwE(event,4, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">减少</nobr>select语句的数量（配置batch-size属性）。对于切左外连接检索，优点在于select较少，但缺点是select语句的复杂度提高，多表之间的关联会是很耗时的操作。另外，配置文件是死的，但<nobr oncontextmenu="return false;" onmousemove="kwM(2);" id="key2" onmouseover="kwE(event,2, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">程序</nobr>是活的，可以根据需要在程序里显示的指定检索策略（可能经常需要在程序中显示指定迫切左外连接检索）。为了清楚检索策略的配置<nobr oncontextmenu="return false;" onmousemove="kwM(0);" id="key0" onmouseover="kwE(event,0, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">效果</nobr>如何，可以配置show_sql属性查看程序运行时Hibernate执行的sql语句。</p>
</div>
<img src ="http://www.blogjava.net/sutao/aggbug/161878.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-11-20 15:59 <a href="http://www.blogjava.net/sutao/articles/161878.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>详细讲解在Hibernate中检索策略的应用</title><link>http://www.blogjava.net/sutao/articles/161879.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Tue, 20 Nov 2007 07:59:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/161879.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/161879.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/161879.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/161879.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/161879.html</trackback:ping><description><![CDATA[<h1 id="pageName">详细讲解在Hibernate中检索策略的应用</h1>
<div class="feature">&nbsp;</div>
<div class="story">
<p>　　<a href="http://www.pcdog.com/special/1202/index.html" target="_blank">Hibernate</a>的检索<nobr oncontextmenu="return false;" onmousemove="kwM(1);" id="key1" onmouseover="kwE(event,1, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">策略</nobr>包括类级别检索策略和关联级别检索策略。</p>
<div class="ad0">　　类级别检索策略有立即检索和延迟检索，默认的检索策略是立即检索。在Hibernate映射文件中，通过在&lt;不着class&gt;上配置lazy属性来确定检索策略。对于Session的检索方式，类级别检索策略仅适用于load方法；也就说，对于get、 qurey检索，持久化对象都会被立即加载而不管lazy是false还是true.一般来说，我们检索对象就是要访问它，因此立即检索是通常的选择。由于load方法在检索不到对象时会抛出异常（立即检索的情况下），因此我个人并不建议使用load检索；而由于&lt; class&gt;中的lazy属性还影响到多对一及一对一的检索策略，因此使用load方法就更没必要了。</div>
<p>　　关联级别检索策略有立即检索、延迟检索和迫切左外连接检索。对于关联级别检索，又可分为一对多和多对多、多对一和一对一两种情况讨论。</p>
<p>　　一对多和多对多关联关系一般使用&lt; set&gt;配置。&lt; set&gt;有lazy和outer-join属性，它们的不同取值绝对了检索策略。</p>
<p>　　1）立即检索：这是一对多默认的检索策略，此时lazy=false，outer-join=false.尽管这是默认的检索策略，但如果关联的集合是无用的，那么就不要使用这种检索方式。</p>
<p>　　2）延迟检索：此时lazy=true，outer-join=false（outer-join=true是无意义的），这是优先考虑的检索方式。</p>
<p>　　3）迫切左外连接检索：此时 lazy=false，outer-join=true，这种检索策略只适用于依靠id检索方式（load、get），而不适用于query的集合检索（它会采用立即检索策略）。相比于立即检索，这种检索策略减少了一条sql语句，但在Hibernate中，只能有一个配置成 outer-join=true.</p>
<p>　　多对一和一对一检索策略一般使用&lt; many-to-one&gt;、&lt; one-to-one&gt;配置。&lt; many-to-one&gt;中需要配置的属性是 outer-join，同时还需要配置one端关联的&lt; class&gt;的lazy属性（配置的可不是&lt; many-to-one&gt;中的lazy哦），它们的组合后的检索策略如下：</p>
<p>　　1） outer-join=auto：这是默认值，如果lazy=true为延迟检索，如果lazy=false为迫切左外连接检索。</p>
<p>　　2） outer-join=true，无关于lazy，都为迫切左外连接检索。</p>
<p>　　3） outer-join=false，如果lazy=true为延迟检索，否则为立即检索。</p>
<p>　　可以看到，在默认的情况下（outer-join=auto，lazy=false），对关联的one端对象Hibernate采用的迫切左外连接检索。依我看，很多情况下，我们并不需要加载one端关联的对象（很可能我们需要的仅仅是关联对象的id）；另外，如果关联对象也采用了迫切左外连接检索，就会出现select语句中有多个外连接表，如果个数多的话会影响检索性能，这也是为什么Hibernate通过 hibernate.max_fetch_depth属性来控制外连接的深度。对于迫切左外连接检索，query的集合检索并不适用，它会采用立即检索策略。</p>
<p>　　对于检索策略，需要根据实际情况进行选择。对于立即检索和延迟检索，它们的优点在于select语句简单（每张表一条语句）、查询速度快，缺点在于关联表时需要多条select语句，增加了访问<a href="http://www.pcdog.com/special/1229/index.html" target="_blank">数据库</a>的频率。因此在选择即检索和延迟检索时，可以考虑使用批量检索策略来<nobr oncontextmenu="return false;" onmousemove="kwM(4);" id="key3" onmouseover="kwE(event,4, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">减少</nobr>select语句的数量（配置batch-size属性）。对于切左外连接检索，优点在于select较少，但缺点是select语句的复杂度提高，多表之间的关联会是很耗时的操作。另外，配置文件是死的，但<nobr oncontextmenu="return false;" onmousemove="kwM(2);" id="key2" onmouseover="kwE(event,2, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">程序</nobr>是活的，可以根据需要在程序里显示的指定检索策略（可能经常需要在程序中显示指定迫切左外连接检索）。为了清楚检索策略的配置<nobr oncontextmenu="return false;" onmousemove="kwM(0);" id="key0" onmouseover="kwE(event,0, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">效果</nobr>如何，可以配置show_sql属性查看程序运行时Hibernate执行的sql语句。</p>
</div>
<img src ="http://www.blogjava.net/sutao/aggbug/161879.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-11-20 15:59 <a href="http://www.blogjava.net/sutao/articles/161879.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用struts+spring+hibernate 组装web应用</title><link>http://www.blogjava.net/sutao/articles/161874.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Tue, 20 Nov 2007 07:50:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/161874.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/161874.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/161874.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/161874.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/161874.html</trackback:ping><description><![CDATA[<h1 id="pageName">使用struts+spring+hibernate 组装web应用</h1>
<div class="feature">
<p>来源：&nbsp;作者：佚名&nbsp;2007-11-02&nbsp;出处：<a href="http://www.pcdog.com/" target="_blank">pcdog.com</a></p>
</div>
<div class="keyword_list">&nbsp;</div>
<div class="story">
<p>&nbsp;&nbsp; &nbsp;其实，就算用<a href="http://www.pcdog.com/special/1198/index.html" target="_blank">Java</a>建造一个不是很烦琐的web应用，也不是件轻松的事情。 在构架的一开始就有很多事情要考虑。 从高处看，摆在<nobr oncontextmenu="return false;" onmousemove="kwM(2);" id="key2" onmouseover="kwE(event,2, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">开发</nobr>者面前有很多问题：要考虑是怎样建立用户接口？在哪里处理业务逻辑？ 怎样持久化的数据。</p>
<div class="ad0">&nbsp; 而这三层构架中，每一层都有他们要仔细考虑的。 各个层该使用什么技术？ 怎样的设计能松散耦合还能灵活改变？ 怎样替换某个层而不影响整体构架？应用<nobr oncontextmenu="return false;" onmousemove="kwM(5);" id="key3" onmouseover="kwE(event,5, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">程序</nobr>如何做各种级别的业务处理（比如事务处理）？ <br />
<br />
&nbsp;&nbsp;&nbsp; 构架一个Web应用需要弄明白好多问题。 幸运的是，已经有不少开发者已经遇到过这类问题，并且建立了处理这类问题的框架。 一个好框架具备以下几点：减轻开发者处理复杂的问题的负担（&#8220;不重复发明轮子&#8221;）； 内部有良好的扩展； 并且有一个支持它的强大的用户团体。好的构架一般有针对性的处理某一类问题，并且能将它做好（Do One Thing well）。然而，你的程序中有几个层可能需要使用特定的框架，已经完成的UI(用户接口) 并不代表你也可以把你的业务逻辑和持久逻辑偶合到你的UI部分。举个例子， 你不该在一个Controller(控制器)里面写JDBC代码作为你的业务逻辑， 这不是控制器应该提供的。 一个UI 控制器应该委派给其它给在UI范围之外的轻量级组件。 好的框架应该能指导代码如何分布。 更重要的是，框架能把开发者从编码中解放出来，使他们能专心于<nobr oncontextmenu="return false;" onmousemove="kwM(6);" id="key4" onmouseover="kwE(event,6, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">应用</nobr>程序的逻辑（这对客户来说很重要）。 <br />
<br />
&nbsp;&nbsp;&nbsp; 这篇文章将讨论怎样结合几种着名的框架来使得你的应用程序做到松弛耦合。 <br />
<br />
&nbsp;&nbsp;&nbsp; 如何建立你的架构，并且怎样让你的各个应用层保持一致。？如何整合框架以便让每个层在以一种松散偶合的方式彼此作用而不用管低层的技术细节？这对我们来说真是一种挑战。 这里讨论一个整合框架的策略( 使用3 种受欢迎的开源框架) ：表示层我们用Struts； 业务层我们用<a href="http://www.pcdog.com/special/1194/index.html" target="_blank">Spring</a>；而持久层则用<a href="http://www.pcdog.com/special/1202/index.html" target="_blank">Hibernate</a>。 你也可以用其他FrameWork替换只要能得到同样的<nobr oncontextmenu="return false;" onmousemove="kwM(0);" id="key0" onmouseover="kwE(event,0, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">效果</nobr>。 见图1 （框架组合示意图） <br />
<br />
</div>
<p align="center"><a href="http://www.pcdog.com/ArtImage/20071102/ti11_1.jpg" target="_blank"><img height="193" alt="使用struts+spring+hibernate 组装web应用（图一）" src="http://www.pcdog.com/ArtImage/20071102/ti11_1.jpg" width="450" border="0" /></a></p>
<br />
应用程序的分层 <br />
<br />
&nbsp;&nbsp;&nbsp; 大部分的Web应用在职责上至少能被分成4层。这四层是：presentation（描述），persistence（持久），business（业务）和domain model（域模块）。每个层在处理程序上都应该有一项明确的责任, 而不应该在功能上与其它层混合，并且每个层要与其它层分开的，但要给他们之间放一个通信接口。我们就从介绍各个层开始，讨论一下这些层应该提供什么，不应该提供什么。 <br />
<br />
表示层(The Presentation Layer) <br />
<br />
&nbsp;&nbsp;&nbsp; 一般来讲，一个典型的Web应用的的末端应该是表示层。 很多Java发者也理解Struts所提供的。 象业务逻辑之类的被打包到org.apache.struts.Action.， 因此，我们很赞成使用Struts这样的框架。 <br />
<br />
下面是Struts所负责的： <br />
<br />
* 管理用户的请求,做出相应的响应。 <br />
<br />
* 提供一个Controller ,委派调用业务逻辑和其它上层处理。 <br />
<br />
* 处理异常，抛给Struts Action <br />
<br />
* 为显示提供一个模型 <br />
<br />
* UI验证。 <br />
<br />
以下条款，不该在Struts显示层的编码中经常出现。 它们与显示层无关的。 <br />
<br />
* 直接的与<a href="http://www.pcdog.com/special/1229/index.html" target="_blank">数据库</a>通信，例如JDBC调用。 <br />
<br />
* 与你应用程序相关联的业务逻辑以及校验。 <br />
<br />
* 事物管理。 <br />
<br />
在表示层引入这些代码，则会带来高偶合和麻烦的维护。 <br />
<br />
持久层(The Persistence Layer) <br />
<br />
&nbsp;&nbsp;&nbsp; 典型的Web应用的另一个末端是持久层。这里通常是程序最容易失控的地方。开发者总是低估构建他们自己的持久框架的挑战性。<a href="http://www.pcdog.com/net/3655/index.html" target="_blank">系统</a>内部的持续层不但需要大量调试时间，而且还经常缺少功能使之变得难以控制，这是持久层的通病。还好有几个ORM开源框架很好的解决了这类问题。尤其是Hibernate。 Hibernate为java提供了OR持久化机制和查询服务, 它还给已经熟悉SQL和JDBC API 的Java开发者一个学习桥梁，他们学习起来很方便。 Hibernate的持久对象是基于POJO和Java collections。此外，使用Hibernate并不妨碍你正在使用的IDE。 <br />
<br />
请看下面的条目，你在持久层编码中需要了解的。 <br />
<br />
* 查询对象的相关<nobr oncontextmenu="return false;" onmousemove="kwM(1);" id="key1" onmouseover="kwE(event,1, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">信息</nobr>的语句。 Hibernate通过一个OO查询语言（HQL）或者正则表达的API来完成查询。 HQL非常类似于SQL-- 只是把SQL里的table和columns用Object和它的fields代替。 你需要学习一些新的HQL语言；不管怎样，他们容易理解而文档也做的很好。 HQL是一种对象查询的自然语言，花很小的代价就能学习它。 <br />
<br />
* 如何存储，更新，删除数据库记录。 <br />
<br />
* 象Hibernate这类的高级ORM框架支持大部分主流数据库，并且他们支持 Parent/child<nobr oncontextmenu="return false;" onmousemove="kwM(7);" id="key5" onmouseover="kwE(event,7, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">关系</nobr>，事物处理，继承和多态。<br />
<br />
<br />
业务层（The Business Layer）&nbsp;<br />
<br />
<div class="ad0">
<div id="ad_pcdog_big"><script type="text/javascript"><!-- google_ad_client="pub-1572879403720716" ; google_ad_width="336;
google_ad_height" = 280; google_ad_format="336x280_as" ; google_ad_type="text_image" ; google_ad_channel="2957605308" ; google_alternate_ad_url="http://www.pcdog.com/js/336.htm" ; google_color_border="F5FAFA" ; google_color_bg="F5FAFA" ; google_color_link="1F3A87" ; google_color_url="0000FF" ; google_color_text="000000" google_language='zh-CN' ;
//--></script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
</script></div>
</div>
&nbsp;&nbsp; 一个典型Web<nobr oncontextmenu="return false;" onmousemove="kwM(4);" id="key3" onmouseover="kwE(event,4, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">应用</nobr>的中间部分是业务层或者服务层。 从编码的视角来看，这层是最容易被忽视的一层。 而我们却往往在UI层或持久层周围看到这些业务处理的代码，这其实是不正确的，因为它导致了<nobr oncontextmenu="return false;" onmousemove="kwM(3);" id="key2" onmouseover="kwE(event,3, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">程序</nobr>代码的紧密偶合，这样一来，随着时间推移这些代码很难维护。幸好，针对这一问题有好几种Frameworks存在。 最受欢迎的两个框架是<a href="http://www.pcdog.com/special/1194/index.html" target="_blank">Spring</a>和PicoContainer。这些为也被称为microcontainers，他们能让你很好的把对象搭配起来。 这两个框架都着手于&#8216;依赖注射&#8217;(dependency injection)(还有我们知道的&#8216;控制反转&#8217;Inversion of Control=IoC)这样的简单概念。这篇文章将关注于Spring的注射（译注：通过一个给定参数的Setter方法来构造Bean,有所不同于Factory）, Spring还提供了Setter Injection(type2)，Constructor Injection(type3)等方式供我们选择。 Spring把程序中所涉及到包含业务逻辑和Dao的Objects——例如transaction management handler（事物管理控制）、Object Factoris(对象工厂)、service objects（服务组件）——都通过<a href="http://www.pcdog.com/special/1303/index.html" target="_blank">XML</a>来配置联系起来。 <br />
<br />
后面我们会举个例子来揭示一下Spring 是怎样运用这些概念。 <br />
<br />
业务层所负责的如下： <br />
<br />
* 处理应用程序的 业务逻辑和业务校验 <br />
<br />
* 管理事物 <br />
<br />
* 允许与其它层相互作用的接口 <br />
<br />
* 管理业务层级别的对象的依赖。 <br />
<br />
* 在显示层和持久层之间增加了一个灵活的机制，使得他们不直接的联系在一起。 <br />
<br />
* 通过揭示 从显示层到业务层之间的Context来得到business services。 <br />
<br />
* 管理程序的执行（从业务层到持久层）。 <br />
<br />
域模块层（The Domain Model Layer ） <br />
&nbsp;&nbsp;&nbsp; 既然我们致力于的是一个不是很复杂的Web的应用， 我们需要一个对象集合，让它在不同层之间移动的。 域模块层由实际需求中的业务对象组成 比如, OrderLineItem , Product等等。 <nobr oncontextmenu="return false;" onmousemove="kwM(1);" id="key1" onmouseover="kwE(event,1, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">开发</nobr>者在这层 不用管那些DTOs，仅关注domain object即可。 例如，<a href="http://www.pcdog.com/special/1202/index.html" target="_blank">Hibernate</a>允许你将<a href="http://www.pcdog.com/special/1229/index.html" target="_blank">数据库</a>中的<nobr oncontextmenu="return false;" onmousemove="kwM(0);" id="key0" onmouseover="kwE(event,0, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">信息</nobr>存放入对象（domain objects），这样你可以在连接断开的情况下把这些数据显示到UI层。 而那些对象也可以返回给持续层，从而在数据库里更新。 而且，你不必把对象转化成DTOs（这可能似的它在不同层之间的在传输过程中丢失），这个模型使得<a href="http://www.pcdog.com/special/1198/index.html" target="_blank">Java</a>开发者能很自然运用OO，而不需要附加的编码。 <br />
<br />
一个简单例子 <br />
<br />
既然我们已经从全局上理解这些组件。 现在就让我们开始实践吧。 我们还是用 Struts，Spring 和Hibernate。这三个框架已经被描述够多了，这里就不重复介绍了。 这篇文章举例指导你如何使用这三个框架整合开发, 并向你揭示一个请求是如何贯穿于各个层的。（从用户的加入一个Order到数据库，显示；进而更新、删除）。 <br />
<br />
&nbsp;&nbsp;&nbsp; 既然每个层是互相作用的，我们就先来创建domain objects。首先，我们要在这些Object中要确定那些是需要持久化的，哪些是提供给business logic，那些是显示接口的设计。下一步，我们将配置我们的持久层并且定义好Hibernate的OR mappings。然后定义好Business Objects。有了这些组成部分之后，我们将 使用Spring把这些连接起来。最后，我们提供给Spring一个持久层，从这个持久层里我们可以知道它是如何与业务逻辑层（business service layer）通信的，以及它是怎样处理其他层抛出的异常的。。 <br />
<br />
域对象层（Domain Object Layer） <br />
<br />
这层是编码的着手点，我们的编码就从这层开始。 例子中Order 与OrderItem 是一个One—To—Many的关系。 下面就是Domain Object Layer的两个对象： <br />
<br />
&#183; com.meagle.bo.Order.java: 包含了一个Order的概要信息 <br />
<br />
&#183; com.meagle.bo.OrderLineItem.java: 包含了Order的详细信息 <br />
<br />
&nbsp;&nbsp;&nbsp; 好好考虑怎你的package命名,这反应出了你是怎样分层的。 例如 domain objects在程序中可能打包在com.meagle.bo内。 更详细一点将打包在com. meagle.bo的子目录下面。business logic应该从com.meagle.serice开始打包，而DAO 对象应该位于com.meagle.service.dao.hibernate。反应Forms和Actions的持久对象（presentation classes） 应该分别放在 com.meagle.action和com.meagle.forms包。准确的给包命名使得你的classes很好分割并且易于维护，并且在你添加新的classes时，能使得程序结构上保持上下一致。 <br />
<br />
持久层的配置（Persistence Layer Configuration） <br />
<br />
&nbsp;&nbsp;&nbsp; 建立Hibernate的持久层 需要好几个步骤。 第一步让我们把BO持久化。 既然Hibernate是通过POJO工作的， 因此Order和 OrderLineItem对象需要给所有的fileds 加上getter,setter方法。 Hibernate通过XML文件来映射(OR)对象，以下两个xml文件分别映射了Order 和OrderItem对象。（这里有个叫XDoclet工具可以自动生成你的XML影射文件） <br />
<br />
- Order.hbm.xml <br />
- OrderLineItem.hbm.xml <br />
<br />
&nbsp;&nbsp;&nbsp; 你可以在WebContent/WEB-INF/classes/com/meagle/bo目录下找到这些xml文件。Hibernate的 [urlhttp://www.hibernate.org/hib_docs/api/net/sf/hibernate/SessionFactory.html]SessionFactory [/url]是用来告诉程序 应该与哪个数据库通信，该使用哪个连接池或使用了DataSource，应该加载哪些持久对象。而Session接口是用来完成Selecting，Saving，Delete和Updating这些操作。后面的我们将讲述SessionFactory和Session是怎样设置的。 <br />
<br />
业务层的配置（Business Layer Configuration） <br />
<br />
&nbsp;&nbsp;&nbsp; 既然我们已经有了domain objects，接下来我们就要business service objects了，用他们来执行程序的logic,调用持久层，得到UI层的requests,处理transactions，并且控制 exceptions。 为了将这些连接起来并且易于管理，我们将使用面向方面的 SpringFramework。 Spring 提供了控制倒置（inversion of control 0==IoC)和注射依赖设置（setter dependency injection）这些方式（可供选择），用XML文件将对象连接起来。 IoC是一个简单概念（它允许一个对象在上层接受其他对象的创建），用IoC这种方式让你的对象从创建中释放了出来，降低了偶合度。 <br />
<br />
&nbsp;&nbsp;&nbsp; 这里是一个没有使用IoC的对象创建的例子，它有很高偶合度。 <br />
<br />
<p align="center"><img height="212" alt="使用struts+spring+hibernate 组装web应用（图二）" src="http://www.pcdog.com/ArtImage/20071102/ti11_2.jpg" width="250" border="0" /></p>
<br />
图 2.没有使用 IoC. A 创建了 B 和 C <br />
<br />
&nbsp;&nbsp;&nbsp; 而这里是一个使用IoC的例子，这种方式允许对象在高层可以创建并进入另外一个对象，所以这样可以直接被执行。 <br />
<br />
<p align="center"><img height="210" alt="使用struts+spring+hibernate 组装web应用（图三）" src="http://www.pcdog.com/ArtImage/20071102/ti11_3.jpg" width="250" border="0" /></p>
<br />
图 3. 对象使用了 IoC。 A 包含了接受B,C的 setter方法 , 这同样达到了 由A创建B,C的目的。 <br />
<br />
建立我们的业务服务对象（Building Our Business Service Objects） <br />
<br />
&nbsp;&nbsp;&nbsp; Business Object中的Setter方法接受的是接口，这样我们可以很松散的定义对象实现，然后注入。在我们的案例中，我们将用一个business service object接收一个DAO,用它来控制domain objects的持久化。由于在这个例子中使用了Hibernate，我们可以很<nobr oncontextmenu="return false;" onmousemove="kwM(5);" id="key4" onmouseover="kwE(event,5, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">方便</nobr>的用其他持久框架实现 同时通知Spring 有新的DAO可以使用了。 <br />
<br />
&nbsp;&nbsp;&nbsp; 在面向接口的编程中，你会明白 &#8220;注射依赖&#8221;模式是怎样松散耦合你的业务逻辑和持久机制的：）。<br />
<br />
<p align="center"><a href="http://www.pcdog.com/ArtImage/20071102/ti11_4.jpg" target="_blank"><img height="352" alt="使用struts+spring+hibernate 组装web应用（图四）" src="http://www.pcdog.com/ArtImage/20071102/ti11_4.jpg" width="436" border="0" /></a></p>
<div class="ad1">
<div id="ad_pcdog_big"><script type="text/javascript"><!-- google_ad_client="pub-1572879403720716" ; google_ad_width="336;
google_ad_height" = 280; google_ad_format="336x280_as" ; google_ad_type="text_image" ; google_ad_channel="2957605308" ; google_alternate_ad_url="http://www.pcdog.com/js/336.htm" ; google_color_border="F5FAFA" ; google_color_bg="F5FAFA" ; google_color_link="1F3A87" ; google_color_url="0000FF" ; google_color_text="000000" google_language='zh-CN' ;
//--></script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript">
</script></div>
</div>
<br />
图 4. Spring就是这样基于配置文件，将各个Bean搭建在一起。 <br />
<br />
这个例子使用一个 TransactionProxyFactoryBean，它定义了一个setTransactionManager()。这对象很有用，他能很方便的处理你申明的事物还有Service Object。你可以通过transactionAttributes属性来定义怎样处理。想知道更多还是参考TransactionAttributeEditor吧。 <br />
<br />
TransactionProxyFactoryBean 还有个setter. 这会被我们 Business service object（orderTarget）引用， orderTarget定义了业务服务层，并且它还有个属性，由setOrderDAO()引用。这个属性&nbsp;<br />
<br />
&nbsp;&nbsp;&nbsp; Spring 和Bean 的还有一点要注意的： bean可以以用两种方式创造。 这些都在单例模式（Sington）和原型模式（propotype）中定义了。默认的方式是singleton,这意味着共享的实例将被束缚。而原形模式是在Spring用到bean的时候允许新建实例的。当每个用户需要得到他们自己Bean的Copy时，你应该仅使用prototype模式。（更多的请参考设计模式中的单例模式和原形模式） <br />
<br />
提供一个服务定位器（Providing a Service Locator） <br />
<br />
&nbsp;&nbsp;&nbsp; 既然我们已经将我们的Serices和DAO搭配起来了。我们需要把我们的Service显示到其他层。 这个通常是在Struts或者<a href="http://www.pcdog.com/net/1279/index.html" target="_blank">Swing</a>这层里<nobr oncontextmenu="return false;" onmousemove="kwM(2);" id="key0" onmouseover="kwE(event,2, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">编码</nobr>。一个简单方法就是用 服务定位器返回给Spring context 。当然，可以通过直接调用Spring中的Bean来做。 <br />
<br />
下面是一个Struts Actin 中的服务定位器的一个例子。 <br />
<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td><strong>代码:</strong></td>
        </tr>
        <tr>
            <td><br />
            public abstract class BaseAction extends Action { <br />
            &nbsp; <br />
            &nbsp; private IOrderService orderService; <br />
            &nbsp; <br />
            &nbsp; public void setServlet(ActionServlet <br />
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;actionServlet) { <br />
            &nbsp; &nbsp; super.setServlet(actionServlet); <br />
            &nbsp; &nbsp; ServletContext servletContext = <br />
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;actionServlet.getServletContext(); <br />
            &nbsp; <br />
            &nbsp; &nbsp; WebApplicationContext wac = <br />
            &nbsp; &nbsp; &nbsp; WebApplicationContextUtils. <br />
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;getRequiredWebApplicationContext( <br />
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;servletContext); <br />
            &nbsp; <br />
            &nbsp; &nbsp; &nbsp; this.orderService = (IOrderService) <br />
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;wac.getBean("orderService"); <br />
            &nbsp; } <br />
            &nbsp; <br />
            &nbsp; protected IOrderService getOrderService() { <br />
            &nbsp; &nbsp; return orderService; <br />
            &nbsp; } <br />
            } </td>
        </tr>
    </tbody>
</table>
<br />
UI 层配置 （UI Layer Configuration） <br />
<br />
&nbsp;&nbsp;&nbsp; 这个例子里UI层 使用了Struts framework. 这里我们要讲述一下在给程序分层的时候， 哪些是和Struts部分的。我们就从一个Struts-config.xml文件中的Action的配置<nobr oncontextmenu="return false;" onmousemove="kwM(1);" id="key1" onmouseover="kwE(event,1, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">信息</nobr>开始吧。 <br />
<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td><strong>代码:</strong></td>
        </tr>
        <tr>
            <td><br />
            struts-config.xml file. <br />
            <br />
            &lt;action path="/SaveNewOrder" <br />
            &nbsp; &nbsp; type="com.meagle.action.SaveOrderAction" <br />
            &nbsp; &nbsp; name="OrderForm" <br />
            &nbsp; &nbsp; scope="request" <br />
            &nbsp; &nbsp; validate="true" <br />
            &nbsp; &nbsp; input="/NewOrder.jsp"&gt; <br />
            &nbsp; &lt;display-name&gt;Save New Order&lt;/display-name&gt; <br />
            &nbsp; &lt;exception key="error.order.save" <br />
            &nbsp; &nbsp; path="/NewOrder.jsp" <br />
            &nbsp; &nbsp; scope="request" <br />
            &nbsp; &nbsp; type="com.meagle.exception.OrderException"/&gt; <br />
            &nbsp; &lt;exception key="error.order.not.enough.money" <br />
            &nbsp; &nbsp; path="/NewOrder.jsp" <br />
            &nbsp; &nbsp; scope="request" <br />
            &nbsp; &nbsp; type="com. <br />
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; meagle. <br />
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; exception. <br />
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; OrderMinimumAmountException"/&gt; <br />
            &nbsp; &lt;forward name="success" path="/ViewOrder.jsp"/&gt; <br />
            &nbsp; &lt;forward name="failure" path="/NewOrder.jsp"/&gt; <br />
            &lt;/action&gt;</td>
        </tr>
    </tbody>
</table>
<br />
&nbsp;&nbsp;&nbsp; SaveNewOrder 这个Action是用来持久化UI层里的表单提交过来Order的。这是Struts中一个很典型的Action; 注意观察这个Action中exception配置，这些Exceptions也在<a href="http://www.pcdog.com/special/1194/index.html" target="_blank">Spring</a> 配置文件(applicationContext-hibernate.xml)中配置了（就在 business service object 的transactionAttributes属性里）。 当异常在业务层被被抛出时，我们可以控制他们，并适当的显示给UI层。 <br />
<br />
&nbsp;&nbsp;&nbsp; 第一个异常，OrderException,在持久层保存order对象失败的时候被触发。这将导致事物回滚并且通过BO把异常回传到Struts这一层。 <br />
<br />
第二个异常，OrderMinimumAmountException也同第一个一样。 <br />
<br />
&nbsp;&nbsp;&nbsp; 搭配整和的最后一步 通过是让你显示层和业务层相结合。这个已经被服务定位器（service locator）实现了（前面讨论过了）， 这里服务层作为一个接口提供给我们的业务逻辑和持久层。 <br />
<br />
&nbsp;&nbsp;&nbsp; SaveNewOrder Action 在Struts中用一个服务定位器（service locator）来调用执行业务方法的。 方法代码如下： <br />
<br />
<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td><strong>代码:</strong></td>
        </tr>
        <tr>
            <td>public ActionForward execute( <br />
            <br />
            &nbsp; ActionMapping mapping, <br />
            <br />
            &nbsp; ActionForm form, <br />
            <br />
            &nbsp; javax.servlet.http.HttpServletRequest request, <br />
            <br />
            &nbsp; javax.servlet.http.HttpServletResponse response) <br />
            <br />
            &nbsp; throws <nobr oncontextmenu="return false;" onmousemove="kwM(0);" id="key0" onmouseover="kwE(event,0, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">java</nobr>.lang.Exception { <br />
            <br />
            &nbsp; <br />
            <br />
            &nbsp; OrderForm oForm = (OrderForm) form; <br />
            <br />
            &nbsp; <br />
            <br />
            &nbsp; // Use the form to build an Order object that <br />
            <br />
            &nbsp; // can be saved in the persistence layer. <br />
            <br />
            &nbsp; // See the full source code in the sample app. <br />
            <br />
            &nbsp; <br />
            <br />
            &nbsp; // Obtain the wired business service object <br />
            <br />
            &nbsp; // from the service locator configuration <br />
            <br />
            &nbsp; // in BaseAction. <br />
            <br />
            &nbsp; // Delegate the save to the service layer and <br />
            <br />
            &nbsp; // further upstream to save the Order object. <br />
            <br />
            &nbsp; getOrderService().saveNewOrder(order); <br />
            <br />
            &nbsp; <br />
            <br />
            &nbsp; oForm.setOrder(order); <br />
            <br />
            &nbsp; <br />
            <br />
            &nbsp; ActionMessages messages = new ActionMessages(); <br />
            <br />
            &nbsp; messages.add( <br />
            <br />
            &nbsp; &nbsp; &nbsp; ActionMessages.GLOBAL_MESSAGE, <br />
            <br />
            &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; new ActionMessage( <br />
            <br />
            &nbsp; &nbsp; &nbsp; "message.order.saved.successfully")); <br />
            <br />
            &nbsp; <br />
            <br />
            &nbsp; saveMessages(request, messages); <br />
            <br />
            &nbsp; <br />
            <br />
            &nbsp; return mapping.findForward("success"); <br />
            <br />
            }</td>
        </tr>
    </tbody>
</table>
<br />
<br />
<strong>总结 <br />
</strong><br />
&nbsp;&nbsp;&nbsp; 文章在技术和构架方面掩盖了很多低层的基础信息， 文章的主要的意图在于让你意识到如何给你<nobr oncontextmenu="return false;" onmousemove="kwM(4);" id="key3" onmouseover="kwE(event,4, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">应用</nobr>程序分层。 分层可以&#8220;解耦&#8221;你的代码——允许新的组件被添加进来，而且让你的代码易于维护。 这里用到的技术只是专注于把&#8220;解偶&#8221;做好。不管怎样，使用这样的构架可以让你用其他技术代替现在的层。例如，你可能不使用Hibernate实现持久化。既然你在DAO中面向接口的编程的，所以你完全可以用iBATIS来代替。或者，你也可能想用 Struts外的其他的技术或者框架替换现在的UI层（转换久层，实现层并不应该直接影响到你的业务逻辑和业务服务层）。用适当的框架搭建你的Web应用，其实也不是一件烦琐的工作，更主要的是它&#8220;解耦&#8221;了你程序中的各个层。 <br />
<br />
后记： <br />
<br />
&nbsp;&nbsp;&nbsp; 这篇文章后，只是觉得很<nobr oncontextmenu="return false;" onmousemove="kwM(5);" id="key4" onmouseover="kwE(event,5, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">喜欢</nobr>，于是就翻译了，当然同时也准备着挨大家扔来的鸡蛋：）。 <br />
<br />
&nbsp;&nbsp;&nbsp; 文章里并没有太多的技术细节，和详细的步骤。如果你从未使用过这些框架而在运行实例程序遇上困难的话，可以到CSDN<nobr oncontextmenu="return false;" onmousemove="kwM(3);" id="key2" onmouseover="kwE(event,3, this);" style="color: rgb(102,0,255); border-bottom: rgb(102,0,255) 1px dotted; background-color: transparent; text-decoration: underline" onclick="return kwC();" onmouseout="kwL(event, this);" target="_blank">论坛</nobr>Java Open Source版发贴，我一定会详细解答的（啊哦，这不算做广告吧？）， <br />
<br />
&nbsp;&nbsp;&nbsp; 文章是从一个构架的角度讲述了如何搭配现有的开源框架进行分层， 有太多的术语我都不知道怎么表达，而且可能有很多语句存在错误。如果影响了你的阅读，请你直接点原文地址，我同时也象你说声抱歉。<br />
</div>
<img src ="http://www.blogjava.net/sutao/aggbug/161874.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-11-20 15:50 <a href="http://www.blogjava.net/sutao/articles/161874.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate延迟加载</title><link>http://www.blogjava.net/sutao/articles/158759.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Wed, 07 Nov 2007 03:02:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/158759.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/158759.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/158759.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/158759.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/158759.html</trackback:ping><description><![CDATA[<p>其实这个异常写的非常之清楚，就是会话关闭，无法对Hibernate实体进行操作。造成这样的情况有很多，什么书写错误啊，逻辑错误啊。</p>
<p>但就此说一下关于lazy机制：</p>
<p><span style="color: purple;">延迟初始化错误是运用Hibernate开发项目时最常见的错误。如果对一个类或者集合配置了延迟检索策略，那么必须当代理类实例或代理集合处于持久化状态（即处于</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong><span style="color: purple;">范围内）时，才能初始化它。如果在游离状态时才初始化它，就会产生延迟初始化错误。<span><br />
<br />
</span>下面把Customer.hbm.xml文件的&lt;class&gt;元素的lazy属性设为true，表示使用延迟检索策略：<span><br />
<br />
&lt;class name="mypack.Customer" table="CUSTOMERS"
lazy="true"&gt;<br />
<br />
</span>当执行</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong><span style="color: purple;">的load()方法时，Hibernate不会立即执行查询CUSTOMERS表的select语句，仅仅返回Customer类的代理类的实例，这个代理类具由以下特征：<span><br />
<br />
</span>（1） 由Hibernate在运行时动态生成，它扩展了Customer类，因此它继承了Customer类的所有属性和方法，但它的实现对于应用程序是透明的。<span><br />
</span>（2） 当Hibernate创建Customer代理类实例时，仅仅初始化了它的OID属性，其他属性都为null，因此这个代理类实例占用的内存很少。<span><br />
</span>（3）当应用程序第一次访问Customer代理类实例时（例如调用customer.getXXX()或customer.setXXX()方法）， Hibernate会初始化代理类实例，在初始化过程中执行select语句，真正从数据库中加载Customer对象的所有数据。但有个例外，那就是当 应用程序访问Customer代理类实例的getId()方法时，Hibernate不会初始化代理类实例，因为在创建代理类实例时OID就存在了，不必 到数据库中去查询。<span><br />
<br />
</span>提示：Hibernate采用CGLIB工具来生成持久化类的代理类。CGLIB是一个功能强大的Java字节码生成工具，它能够在程序运行时动态生成扩
展 Java类或者实现Java接口的代理类。关于CGLIB的更多知识，请参考：http://cglib.sourceforge.net/。<span><br />
<br />
</span>以下代码先通过</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong><span style="color: purple;">的load()方法加载Customer对象，然后访问它的name属性：<span> <br />
<br />
tx = </span></span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong><span style="color: purple;">.beginTransaction();<br />
Customer customer=(Customer)</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong><span style="color: purple;">.load(Customer.class,new Long(1));<br />
customer.getName();<br />
tx.commit();<br />
<br />
</span><span style="color: purple;">在运行</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong><span style="color: purple;">.load ()</span><span style="color: purple;">方法时Hibernate不执行任何select语句，仅仅返回Customer类的代理类的实例，它的OID为1，这是由load()方法的第二个 参数指定的。当应用程序调用customer.getName()方法时，Hibernate会初始化Customer代理类实例，从数据库中加载 Customer对象的数据，执行以下select语句：<span><br />
<br />
select * from CUSTOMERS where ID=1;<br />
select * from ORDERS where CUSTOMER_ID=1;<br />
<br />
</span>当&lt;class&gt;元素的lazy属性为true，会影响</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong><span style="color: purple;">的load()方法的各种运行时行为，下面举例说明。<span><br />
<br />
1</span>．如果加载的Customer对象在数据库中不存在，</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong><span style="color: purple;">的load()方法不会抛出异常，只有当运行customer.getName()方法时才会抛出以下异常：<span><br />
<br />
ERROR LazyInitializer:63 </span></span><strong><span style="background: #ff66ff none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong><span style="color: purple;"> Exception initializing </span><strong><span style="background: #ff9999 none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">proxy</span></strong><span><br />
<span style="color: purple;">net.sf.hibernate.ObjectNotFoundException: No row
with </span><strong><span style="background: #880000 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">the</span></strong><span style="color: purple;">
given identifier exists: 1, of class: <br />
mypack.Customer<br />
<br />
2</span></span><span style="color: purple;">．如果在整个</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong><span style="color: purple;">范围内，应用程序没有访问过Customer对象，那么Customer代理类的实例一直不会被初始化，Hibernate不会执行任何select语句。以下代码试图在关闭</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong><span style="color: purple;">后访问Customer游离对象：<span><br />
<br />
tx = </span></span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong><span style="color: purple;">.beginTransaction();<br />
Customer customer=(Customer)</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong><span style="color: purple;">.load(Customer.class,new Long(1));<br />
tx.commit();<br />
</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong><span style="color: purple;">.close();<br />
customer.getName();<br />
<br />
</span><span style="color: purple;">由于引用变量customer引用的Customer代理类的实例在</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong><span style="color: purple;">范围内始终没有被初始化，因此在执行customer.getName()方法时，Hibernate会抛出以下异常：<span><br />
<br />
ERROR LazyInitializer:63 </span></span><strong><span style="background: #ff66ff none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong><span style="color: purple;"> Exception initializing </span><strong><span style="background: #ff9999 none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">proxy</span></strong><span><br />
<span style="color: purple;">net.sf.hibernate.HibernateException: </span><strong><span style="background: #ffff66 none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Could</span></strong><strong><span style="background: #a0ffff none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">not</span></strong><strong><span style="background: #99ff99 none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">initialize</span></strong><strong><span style="background: #ff9999 none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">proxy</span></strong><strong><span style="background: #ff66ff none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong><strong><span style="background: #880000 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">the</span></strong><strong><span style="background: #00aa00 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">owning</span></strong><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong><strong><span style="background: #004699 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">was</span></strong><strong><span style="background: #990099 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">closed</span></strong><br />
<br />
</span><span style="color: purple;">由此可见，Customer代理类的实例只有在当前</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong><span style="color: purple;">范围内才能被初始化。<span><br />
<br />
3</span>．net.sf.hibernate.Hibernate类的</span><strong><span style="background: #99ff99 none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">initialize</span></strong><span style="color: purple;">()</span><span style="color: purple;">静态方法用于在</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong><span style="color: purple;">范围内显式初始化代理类实例，isInitialized()方法用于判断代理类实例是否已经被初始化。例如：<span><br />
<br />
tx = </span></span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong><span style="color: purple;">.beginTransaction();<br />
Customer customer=(Customer)</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong><span style="color: purple;">.load(Customer.class,new Long(1));<br />
if(!Hibernate.isInitialized(customer)) <br />
Hibernate.</span><strong><span style="background: #99ff99 none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">initialize</span></strong><span style="color: purple;">(customer);<br />
tx.commit();<br />
</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong><span style="color: purple;">.close();<br />
customer.getName();<br />
<br />
</span><span style="color: purple;">以上代码在</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong><span style="color: purple;">范围内通过Hibernate类的</span><strong><span style="background: #99ff99 none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">initialize</span></strong><span style="color: purple;">()</span><span style="color: purple;">方法显式初始化了Customer代理类实例，因此当</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong><span style="color: purple;">关闭后，可以正常访问Customer游离对象。<span><br />
<br />
4</span>．当应用程序访问代理类实例的getId()方法时，不会触发Hibernate初始化代理类实例的行为，例如：<span><br />
<br />
tx = </span></span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong><span style="color: purple;">.beginTransaction();<br />
Customer customer=(Customer)</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong><span style="color: purple;">.load(Customer.class,new Long(1));<br />
customer.getId();<br />
tx.commit();<br />
</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong><span style="color: purple;">.close();<br />
customer.getName();<br />
<br />
</span><span style="color: purple;">当应用程序访问customer.getId()方法时，该方法直接返回Customer代理类实例的OID值，无需查询数据库。由于引用变量 customer始终引用的是没有被初始化的Customer代理类实例，因此当</span><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong><span style="color: purple;">关闭后再执行customer.getName()方法， Hibernate会抛出以下异常：</span></p>
<p><span style="color: purple;">ERROR LazyInitializer:63 </span><strong><span style="background: #ff66ff none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong><span style="color: purple;">
Exception initializing </span><strong><span style="background: #ff9999 none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">proxy</span></strong><span><br />
<span style="color: purple;">net.sf.hibernate.HibernateException: </span><strong><span style="background: #ffff66 none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Could</span></strong><strong><span style="background: #a0ffff none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">not</span></strong><strong><span style="background: #99ff99 none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">initialize</span></strong><strong><span style="background: #ff9999 none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">proxy</span></strong><strong><span style="background: #ff66ff none repeat scroll 0% 50%; font-family: 宋体; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong><strong><span style="background: #880000 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">the</span></strong><strong><span style="background: #00aa00 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">owning</span></strong><strong><span style="background: #886800 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong><strong><span style="background: #004699 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">was</span></strong><strong><span style="background: #990099 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">closed</span></strong></span></p>
<p><strong><span style="background: #990099 none repeat scroll 0% 50%; font-family: 宋体; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">解决方法：</span></strong></p>
<p>由于hibernate采用了lazy=true,这样当你用hibernate查询时,返回实际为利用cglib增强的代理类,但其并没有实际填 充;当你在前端,利用它来取值(getXXX)时,这时Hibernate才会到数据库执行查询,并填充对象,但此时如果和这个代理类相关的<strong><span style="background: #886800 none repeat scroll 0% 50%; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong>已关闭掉,就会产生种错误<span>.<br />
</span>在做一对多时，有时会出现"<strong><span style="background: #ffff66 none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">could</span></strong> <strong><span style="background: #a0ffff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">not</span></strong> <strong><span style="background: #99ff99 none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">initialize</span></strong>
<strong><span style="background: #ff9999 none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">proxy</span></strong> <strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong> clothe <strong><span style="background: #00aa00 none repeat scroll 0% 50%; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">owning</span></strong> <strong><span style="background: #886800 none repeat scroll 0% 50%; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong> <strong><span style="background: #004699 none repeat scroll 0% 50%; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">was</span></strong> sed,这个好像是hibernate的缓存问题.问题解决:需要在&lt;many<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>to<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>one&gt;里设置lazy="false". 但有可能会引发另一个异常叫</p>
<p>failed to lazily <strong><span style="background: #99ff99 none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">initialize</span></strong> a collection of role: XXXXXXXX, no <strong><span style="background: #886800 none repeat scroll 0% 50%; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong> or <strong><span style="background: #886800 none repeat scroll 0% 50%; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong> <strong><span style="background: #004699 none repeat scroll 0% 50%; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">was</span></strong> <strong><span style="background: #990099 none repeat scroll 0% 50%; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">closed</span></strong></p>
<p>此异常解决方案请察看本人博客（<a href="http://hi.baidu.com/kekemao1">http://hi.baidu.com/kekemao1</a>）的Hibernate异常中的《failed to lazily <strong><span style="background: #99ff99 none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">initialize</span></strong> a collection of
role异常》<span><br />
<br />
?<br />
</span>解决方法:在web.xml中加入<span><br />
&lt;filter&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;filter<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>name&gt;hibernateFilter&lt;/filter<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>name&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;filter<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>class&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter<br />
&nbsp;&nbsp;&nbsp; &lt;/filter<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>class&gt;<br />
&lt;/filter<br />
&lt;filter<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>mapping&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;filter<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>name&gt;hibernateFilter&lt;/filter<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>name&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;url<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>pattern&gt;*.do&lt;/url<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>pattern&gt;<br />
&lt;/filter<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>mapping&gt;<br />
</span>就可以了;</p>
<p>参考了<span>:<br />
Hibernate</span>与延迟加载：</p>
<p>Hibernate对象关系映射提供延迟的与非延迟的对象初始化。非延迟加载在读取一个对象的时候会将与这个对象所有相关的其他对象一起读取出来。
这有时会导致成百的（如果不是成千的话）select语句在读取对象的时候执行。这个问题有时出现在使用双向关系的时候，经常会导致整个数据库都在初始化
的阶段被读出来了。当然，你可以不厌其烦地检查每一个对象与其他对象的关系，并把那些最昂贵的删除，但是到最后，我们可能会因此失去了本想在ORM工具中 获得的便利。</p>
<p><span><br />
</span>一个明显的解决方法是使用Hibernate提供的延迟加载机制。这种初始化策略只在一个对象调用它的一对多或多对多关系时才将关系对象读取出来。这个过
程对开发者来说是透明的，而且只进行了很少的数据库操作请求，因此会得到比较明显的性能提升。这项技术的一个缺陷是延迟加载技术要求一个 Hibernate会话要在对象使用的时候一直开着。这会成为通过使用DAO模式将持久层抽象出来时的一个主要问题。为了将持久化机制完全地抽象出来，所
有的数据库逻辑，包括打开或关闭会话，都不能在应用层出现。最常见的是，一些实现了简单接口的DAO实现类将数据库逻辑完全封装起来了。一种快速但是笨拙
的解决方法是放弃DAO模式，将数据库连接逻辑加到应用层中来。这可能对一些小的应用程序有效，但是在大的系统中，这是一个严重的设计缺陷，妨碍了系统的
可扩展性。</p>
<p>在Web层进行延迟加载</p>
<p>幸运的是，Spring框架为Hibernate延迟加载与DAO模式的整合提供了一种方便的解决方法。对那些不熟悉Spring与 Hibernate集成使用的人，我不会在这里讨论过多的细节，但是我建议你去了解Hibernate与Spring集成的数据访问。以一个Web应用为 例，Spring提供了OpenSessionInViewFilter和OpenSessionInViewInterceptor。我们可以随意选择 一个类来实现相同的功能。两种方法唯一的不同就在于interceptor在Spring容器中运行并被配置在web应用的上下文中，而Filter在<span>
Spring</span>之前运行并被配置在web.xml中。不管用哪个，他们都在请求将当前会话与当前（数据库）线程绑定时打开Hibernate会话。一旦已绑 定到线程，这个打开了的Hibernate会话可以在DAO实现类中透明地使用。这个会话会为延迟加载数据库中值对象的视图保持打开状态。一旦这个逻辑视 图完成了，Hibernate会话会在Filter的doFilter方法或者Interceptor的postHandle方法中被关闭。下面是每个组 件的配置示例：</p>
<p><span><br />
Interceptor</span>的配置:</p>
<p><span>&lt;beans&gt; <br />
&lt;bean id="urlMapping" <br />
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"&gt;
<br />
&lt;property name="interceptors"&gt; <br />
&lt;list&gt; <br />
&lt;ref bean="openSessionInViewInterceptor"/&gt; <br />
&lt;/list&gt; <br />
&lt;/property&gt; <br />
&lt;property name="mappings"&gt; <br />
<br />
&lt;/bean&gt; <br />
<br />
&lt;bean name="openSessionInViewInterceptor" <br />
class="org.springframework.orm.hibernate.support.OpenSessionInViewInterceptor"&gt;
<br />
&lt;property name="sessionFactory"&gt;&lt;ref
bean="sessionFactory"/&gt;&lt;/property&gt; <br />
&lt;/bean&gt; <br />
&lt;/beans&gt; </span></p>
<p>Filter的配置</p>
<p>&lt;web<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>app&gt;
<br />
<br />
&lt;filter&gt; <br />
&lt;filter<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>name&gt;hibernateFilter&lt;/filter<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>name&gt; <br />
&lt;filter<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>class&gt;
<br />
org.springframework.orm.hibernate.support.OpenSessionInViewFilter <br />
&lt;/filter<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>class&gt;
<br />
&lt;/filter&gt; <br />
<br />
&lt;filter<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>mapping&gt;
<br />
&lt;filter<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>name&gt;hibernateFilter&lt;/filter<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>name&gt; <br />
&lt;url<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>pattern&gt;*.
spring &lt;/url<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>pattern&gt;
<br />
&lt;/filter<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>mapping&gt;
<br />
<br />
&lt;/web<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>app&gt; </p>
<p><span><br />
</span>实现Hibernate的Dao接口来使用打开的会话是很容易的。事实上，如果你已经使用了Spring框架来实现你的Hibernate Dao,很可能你不需要改变任何东西。方便的HibernateTemplate公用组件使访问数据库变成小菜一碟，而DAO接口只有通过这个组件才可以
访问到数据库。下面是一个示例的DAO：</p>
<p><span><br />
public class HibernateProductDAO extends HibernateDaoSupport implements
ProductDAO { </span></p>
<p><span>public Product getProduct(Integer productId) { <br />
return (Product)getHibernateTemplate().load(Product.class, productId); <br />
} </span></p>
<p><span>public Integer saveProduct(Product product) { <br />
return (Integer) getHibernateTemplate().save(product); <br />
} </span></p>
<p><span>public void updateProduct(Product product) { <br />
getHibernateTemplate().update(product); <br />
} <br />
} </span></p>
<p>在业务逻辑层中使用延迟加载</p>
<p>即使在视图外面，Spring框架也通过使用AOP 拦截器 HibernateInterceptor来使得延迟加载变得很容易实现。这个<span>Hibernate
</span>拦截器透明地将调用配置在Spring应用程序上下文中的业务对象中方法的请求拦截下来，在调用方法之前打开一个Hibernate会话，然后在方法执行 完之后将会话关闭。让我们来看一个简单的例子，假设我们有一个接口BussinessObject：</p>
<p><span><br />
public&nbsp;&nbsp;&nbsp;&nbsp; interface&nbsp;&nbsp;&nbsp;
BusinessObject&nbsp;&nbsp;&nbsp;&nbsp; { <br />
public&nbsp;&nbsp;&nbsp;&nbsp; void&nbsp;&nbsp;&nbsp;
doSomethingThatInvolvesDaos(); <br />
} <br />
</span>类BusinessObjectImpl实现了BusinessObject接口:</p>
<p><span>public&nbsp;&nbsp;&nbsp;&nbsp; class&nbsp;&nbsp;&nbsp;
BusinessObjectImpl&nbsp;&nbsp;&nbsp; implements&nbsp;&nbsp;&nbsp;
BusinessObject&nbsp;&nbsp;&nbsp;&nbsp; { <br />
public&nbsp;&nbsp;&nbsp;&nbsp; void&nbsp;&nbsp;&nbsp;
doSomethingThatInvolvesDaos()&nbsp;&nbsp;&nbsp;&nbsp; { <br />
//&nbsp;&nbsp;&nbsp; lots of logic that calls <br />
//&nbsp;&nbsp;&nbsp; DAO classes Which access <br />
//&nbsp;&nbsp;&nbsp; data objects lazily&nbsp;&nbsp;<br />
}&nbsp;&nbsp;<br />
}&nbsp;&nbsp;</span></p>
<p><span><br />
</span>通过在Spring应用程序上下文中的一些配置，我们可以让将调用BusinessObject的方法拦截下来，再令它的方法支持延迟加载。看看下面的一个程序片段：</p>
<p><span><br />
&lt;beans&gt; <br />
&lt;bean id="hibernateInterceptor"
class="org.springframework.orm.hibernate.HibernateInterceptor"&gt; <br />
&lt;property name="sessionFactory"&gt; <br />
&lt;ref bean="sessionFactory"/&gt; <br />
&lt;/property&gt; <br />
&lt;/bean&gt; <br />
&lt;bean id="businessObjectTarget"
class="com.acompany.BusinessObjectImpl"&gt; <br />
&lt;property name="someDAO"&gt;&lt;ref
bean="someDAO"/&gt;&lt;/property&gt; <br />
&lt;/bean&gt; <br />
&lt;bean id="businessObject"
class="org.springframework.aop.framework.ProxyFactoryBean"&gt; <br />
&lt;property name="target"&gt;&lt;ref
bean="businessObjectTarget"/&gt;&lt;/property&gt; <br />
&lt;property name="proxyInterfaces"&gt; <br />
&lt;value&gt;com.acompany.BusinessObject&lt;/value&gt; <br />
&lt;/property&gt; <br />
&lt;property name="interceptorNames"&gt; <br />
&lt;list&gt; <br />
&lt;value&gt;hibernateInterceptor&lt;/value&gt; <br />
&lt;/list&gt; <br />
&lt;/property&gt; <br />
&lt;/bean&gt; <br />
&lt;/beans&gt;</span></p>
<p>当businessObject被调用的时候，HibernateInterceptor打开一个Hibernate会话，并将调用请求传递给 BusinessObjectImpl对象。当BusinessObjectImpl执行完成后，HibernateInterceptor透明地关闭了
会话。应用层的代码不用了解任何持久层逻辑，还是实现了延迟加载。</p>
<p><span><br />
</span>在单元测试中测试延迟加载</p>
<p>最后，我们需要用J<strong><span style="background: #ff66ff none repeat scroll 0% 50%; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">-</span></strong>Unit来测试我们的延迟加载程序。我们可以轻易地通过重写TestCase类中的setUp和tearDown方法来实现这个要求。我比较喜欢用这个方便的抽象类作为我所有测试类的基类。</p>
<p><span><br />
public abstract class MyLazyTestCase extends TestCase { </span></p>
<p><span>private SessionFactory sessionFactory; <br />
private <strong><span style="background: #886800 none repeat scroll 0% 50%; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong> <strong><span style="background: #886800 none repeat scroll 0% 50%; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong>; </span></p>
<p><span>public void setUp() throws Exception { <br />
super.setUp(); <br />
SessionFactory sessionFactory = (SessionFactory)
getBean("sessionFactory"); <br />
<strong><span style="background: #886800 none repeat scroll 0% 50%; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">session</span></strong> =
SessionFactoryUtils.getSession(sessionFactory, true); <br />
<strong><span style="background: #886800 none repeat scroll 0% 50%; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong> s =
sessionFactory.openSession(); <br />
TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(s));
</span></p>
<p>} </p>
<p><span>protected Object getBean(String beanName) { <br />
//Code to get objects from Spring application context <br />
} </span></p>
<p><span>public void tearDown() throws Exception { <br />
super.tearDown(); <br />
SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory);
<br />
<strong><span style="background: #886800 none repeat scroll 0% 50%; color: white; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;">Session</span></strong> s =
holder.getSession(); <br />
s.flush(); <br />
TransactionSynchronizationManager.unbindResource(sessionFactory); <br />
SessionFactoryUtils.closeSessionIfNecessary(s, sessionFactory); <br />
} <br />
}</span></p>
<img src ="http://www.blogjava.net/sutao/aggbug/158759.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-11-07 11:02 <a href="http://www.blogjava.net/sutao/articles/158759.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对session对象在web开发中的创建以及sessionId生成并返回客户端的运行机制.</title><link>http://www.blogjava.net/sutao/articles/158756.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Wed, 07 Nov 2007 02:54:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/158756.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/158756.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/158756.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/158756.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/158756.html</trackback:ping><description><![CDATA[首先谈一下对session对象在web开发中的创建以及sessionId生成并返回客户端的运行机制.<br />
<br />
session对象当客户端首次访问时,创建一个新的session对象.并同时生成一个sessionId,并在此次响应中将sessionId以响应报文的方式些回客户端浏览器内存或以重写url方式送回客户端,来保持整个会话,只要sever端的这个session对象没有销毁,以后再调用request.getSession() 时就直接根据客户端的sessionId来检索server端生成的session对象并返回,不会再次去新建,除非根据此sessionId没有检索到 session对象.<br />
<br />
下面是在IE下测试,因为IE6.0的一个BUG就是IE的隐私设置即使是阻止所有cookie时,也还是会以会话cookie来保存sessionId.所以下面都是以会话cookie来讨论的,<br />
<br />
(1)在server没有关闭,并在session对象销毁时间内,当客户端再次来请求server端的servlet或jsp时, 将会将在第一次请求时生成的sessionId并附带在请求信息头中并向server端发送,server端收到sessionId后根据此 sessionId会去搜索(此过程是透明的)server对应的session对象并直接返回这个session对象,此时不会重新去建立一个新的 session对象.<br />
<br />
(2)当server关闭(之前产生的session对象也就消亡了),或session对象过了其销毁时间后, 浏览器窗口不关,并在本浏览器窗口再次去请求sever端的servlet和jsp时,此时同样会将sessionId(server关闭或 session销毁时生成的sessionId)发送到server端,server根据sessionId去找其对应的session对象,但此时 session对象已经不存在,此时会重新生成一个新的session对象,并生成新的sessionId并同样将这个新生成的sessionId以响应报文的形式送到浏览器内存中.<br />
<br />
(3)当server没有关闭,并session对象在其销毁时间内,当请求一个jsp页面回客户端后, 关闭此浏览器窗口,此时其内存中的sessionId也就随之销毁,在重新去请求sever端的servlet或jsp时,会重新生成一个 sessionId给客户端浏览器,并存在浏览内存中.<br />
<br />
上面的理论在servlet中测试都是成立的,下面谈一下在struts框架下进行上面的测试时的不同的地方.<br />
<br />
先简要说下测试程序的流程:<br />
<br />
客户端请求index.do---&gt;进入server端的IndexAction---&gt;转向login.jsp页面-----&gt;请求login.do-----&gt;进入server端的LoginAction.<br />
<br />
首先说明:IndexAction中没有去产生session对象,login.jsp中设置.<br />
<br />
(1)环境servlet + jsp:<br />
<br />
在sevlet+jsp测试跟踪时,在index.do进入IndexAction后转向login.jsp时,此时浏览器内存中是没有会话cookie的,那么在login.jsp上请求login.do进入LoginAction后,用request.getCookies()测试时,其值是为null的!结果是稳合的,因为从始置终没有产生过session嘛!<br />
<br />
(2)环境struts + jsp:<br />
<br />
在struts+jsp测试跟踪时,跟上面的流程一样,开始想结果也应该是一样的,但经过调试后发现结果却不是所想的那样.在login.do进入 LoginActoin后用,用request.getCookies()测试时,发现其值不为null,即其有name和value,开始很不理解,因为根本就没有创建过session对象,哪来的会话cookie值呢.但是结果有,那么想着此时浏览器内存中也就应该有会话cookie,问题就在这里! 从哪里来的?<br />
<br />
后来经过仔细考虑后,想到struts中的特点,我们自己写的Action类是继承struts的Action的,而且之前是经过struts的中央控制器ActionServlet来控制转向的,所以我想肯定是在程序进入我自己写的IndexAction之前, struts框架中的代码肯定已经创建了session对象并已经生成了sessionId.于是就找到相关书籍查看了ActionServlet工作流程以及调用哪些类,看了之后果然在其中看到了HttpSession session = request.getSession();这样一句话!于是答案也就明了了.<br />
<br />
大家知道struts的ActionServlet类中在接收到我们客户端的请求(*.do)后(之前会做一系列初始化工作),并不是直接去处理我们的请求并调用相应的Action(我们写的如 IndexAction),而是将处理工作交给RequestProcessor类,其process方法中会调用一系列的方法来完成相应的请求处理和转向操作.其中有一个方法引起了我的关注,就是processLocale()方法.<br />
<br />
<br />
<br />
Struts框架:RequestProcess类中的processLocale()方法原型如下:<br />
<br />
程序代码:<br />
protected void processLocale(HttpServletRequest request,<br />
HttpServletResponse response) {<br />
// Are we configured to select the Locale automatically?<br />
if (!moduleConfig.getControllerConfig().getLocale()) {<br />
return;<br />
}<br />
// Has a Locale already been selected?<br />
HttpSession session = request.getSession();<br />
if (session.getAttribute(Globals.LOCALE_KEY) != null) {<br />
return;<br />
}<br />
// Use the Locale returned by the servlet container (if any)<br />
Locale locale = request.getLocale();<br />
if (locale != null) {<br />
if (log.isDebugEnabled()) {<br />
log.debug(" Setting user locale '" + locale + "'");<br />
}<br />
session.setAttribute(Globals.LOCALE_KEY, locale);<br />
}<br />
}<br />
<br />
此类在struts-config.xml配置文件中有对应的配置项: &lt; controller locale="true"&gt;&lt; /controller&gt; 其缺省状态locale属性的值为true,也就会调用processLocale方法,并在第一次请求时创建session对象和生成 sessionId.但改为false后,在第一次请求到达ActionServlet后不会调用processLocale方法,也就不会生成 session对象了。<br />
<br />
结果也就出来了，在struts应用中,*.do到达server端后经过ActionServlet后转想我们自己写的IndexAction之前, &lt; controller locale="true"&gt;&lt; /controller&gt;(缺省状态) 时,就已经产生了session对象和sessionId,这是struts框架类中生成的,即使我们在IndexAction中写上 HttpSession session = request.getSession();其也是RequestProcess类中的processLocale()方法生成的,此时其session 的isNew也还是true,因为还没有返回客户端,其是新创建的,那么按照上面的流程,当在login.jsp上通过login.do进入 LoginAction后,其request.getCookies()固然也就有值了!并且其值是RequestProcess类中的 processLocale()方法产生session对象时生成的.<br />
<br />
如果我们在struts-config.xml中加上&lt; controller locale="false"&gt;&lt; /controller&gt; 时,此时如果再根据上面的流程来跟踪程序,并在LoginAction用request.getCookies()测试时,其值是为null的,当然在 IndexAction写上HttpSession session = request.getSession();时其是进入IndexAction时新创建的,isNew也是true。<br />
<br />
<br />
<br />
<br />
察看了JBOSS的源代码，命名服务器抛出的这个异常分析如下&nbsp; &nbsp;<br />
&nbsp; java.net.SocketException:&nbsp;&nbsp; Software&nbsp;&nbsp; caused&nbsp;&nbsp; connection&nbsp;&nbsp; abort:&nbsp;&nbsp; socket&nbsp;&nbsp; write&nbsp;&nbsp; error&nbsp; &nbsp;<br />
&nbsp; at&nbsp;&nbsp; java.net.SocketOutputStream.socketWrite0(Native&nbsp;&nbsp; Method)&nbsp; &nbsp;<br />
&nbsp; at&nbsp;&nbsp; java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)&nbsp; &nbsp;<br />
&nbsp; at&nbsp;&nbsp; java.net.SocketOutputStream.write(SocketOutputStream.java:136)&nbsp; &nbsp;<br />
&nbsp; at&nbsp;&nbsp; java.io.ObjectOutputStream$BlockDataOutputStream.drain(ObjectOutputStream.java:1639)&nbsp; &nbsp;<br />
&nbsp; at&nbsp;&nbsp; java.io.ObjectOutputStream$BlockDataOutputStream.setBlockDataMode(ObjectOutputStream.java:1548)&nbsp; &nbsp;<br />
&nbsp; at&nbsp;&nbsp; java.io.ObjectOutputStream.writeNonProxyDesc(ObjectOutputStream.java:1146)&nbsp; &nbsp;<br />
&nbsp; at&nbsp;&nbsp; java.io.ObjectOutputStream.writeClassDesc(ObjectOutputStream.java:1100)&nbsp; &nbsp;<br />
&nbsp; at&nbsp;&nbsp; java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1241)&nbsp; &nbsp;<br />
&nbsp; at&nbsp;&nbsp; java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1052)&nbsp; &nbsp;<br />
&nbsp; at&nbsp;&nbsp; java.io.ObjectOutputStream.writeFatalException(ObjectOutputStream.java:1355)&nbsp; &nbsp;<br />
&nbsp; at&nbsp;&nbsp; java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:281)&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;<br />
&nbsp; 上述异常是由于这样的原因造成的：&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;<br />
&nbsp; 1、 客户端进行查找是NamingContext会建立到命名服务器的Socket连接。（此连接是带读取超时的！）&nbsp; &nbsp;<br />
&nbsp; 2、 服务器接收了客户端的连接，使客户端可以继续向下运行。于是客户端运行到ObjectInputStream的readObject处，并等待。此时，客户端是想要得到NamingServer的stub。&nbsp; &nbsp;<br />
&nbsp; 3、 服务端由于线程繁忙，迟迟不能将客户端需要的stub写入ObjectOutputStream。于是客户端等待超时，然后客户端抛出异常。如果此查找操作是在登录操作，客户在登录失败后选择推出程序。则Socket被关闭。&nbsp; &nbsp;<br />
&nbsp; 4、 服务端闲下来后调用ObjectOutputStream的writeObject方法，此时由于客户端Socket关闭，最终抛出上述异常。&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;<br />
&nbsp; 这是我们公司的一个牛人分析的，后来察看了JMS也存在类似问题。另：JBOSS的源代码质量不高，JNDI中存在socket未关闭的情况，JMS代码中socket用法也很不规范。大家小心了&nbsp; <br />
<br />
<br />
<br />
<br />
Hibernate构架应用中常用保存方式区别<br />
Tag：数据库&nbsp; pda&nbsp; ie&nbsp; hibernate &nbsp;<br />
下一页 1 2 <br />
<br />
hibernate对于对象的保存提供了太多的方法，他们之间有很多不同，这里细说一下，以便区别：<br />
<br />
一、预备知识：<br />
<br />
在所有之前，说明一下，对于hibernate，它的对象有三种状态，transient、persistent、detached<br />
<br />
下边是常见的翻译办法：<br />
<br />
transient：瞬态或者自由态<br />
<br />
persistent：持久化状态<br />
<br />
detached：脱管状态或者游离态<br />
<br />
脱管状态的实例可以通过调用save（）、persist（）或者saveOrUpdate（）方法进行持久化。<br />
<br />
持久化实例可以通过调用 delete（）变成脱管状态。通过get（）或load（）方法得到的实例都是持久化状态的。<br />
<br />
脱管状态的实例可以通过调用 update（）、0saveOrUpdate（）、lock（）或者replicate（）进行持久化。<br />
<br />
save（）和persist（）将会引发SQL的INSERT，delete（）会引发SQLDELETE，而update（）或merge（）会引发SQLUPDATE.对持久化（persistent）实例的修改在刷新提交的时候会被检测到，它也会引起 SQLUPDATE.saveOrUpdate（）或者replicate（）会引发SQLINSERT或者UPDATE<br />
<br />
二、save 和update区别<br />
<br />
把这一对放在第一位的原因是因为这一对是最常用的。<br />
<br />
save的作用是把一个新的对象保存<br />
<br />
update是把一个脱管状态的对象保存<br />
<br />
三、update 和saveOrUpdate区别<br />
<br />
这个是比较好理解的，顾名思义，saveOrUpdate基本上就是合成了save和update引用hibernate reference中的一段话来解释他们的使用场合和区别。<br />
<br />
通常下面的场景会使用update（）或saveOrUpdate（）：<br />
<br />
程序在第一个session中加载对象<br />
<br />
该对象被传递到表现层<br />
<br />
对象发生了一些改动<br />
<br />
该对象被返回到业务逻辑层<br />
<br />
程序调用第二个session的update（）方法持久这些改动<br />
<br />
saveOrUpdate（）做下面的事：<br />
<br />
如果对象已经在本session中持久化了，不做任何事<br />
<br />
如果另一个与本session关联的对象拥有相同的持久化标识（identifier），抛出一个异常<br />
<br />
如果对象没有持久化标识（identifier）属性，对其调用save（）<br />
<br />
如果对象的持久标识（identifier）表明其是一个新实例化的对象，对其调用save（）<br />
<br />
如果对象是附带版本信息的（通过或） 并且版本属性的值表明其是一个新实例化的对象，save（）它。<br />
<br />
四、persist和save区别<br />
<br />
这个是最迷离的一对，表面上看起来使用哪个都行，在hibernate reference文档中也没有明确的区分他们。<br />
<br />
这里给出一个明确的区分。（可以跟进src看一下，虽然实现步骤类似，但是还是有细微的差别）<br />
<br />
1.persist把一个瞬态的实例持久化，但是并"不保证"标识符被立刻填入到持久化实例中，标识符的填入可能被推迟到flush的时间。<br />
<br />
2.persist"保证"，当它在一个transaction外部被调用的时候并不触发一个Sql Insert，这个功能是很有用的，当我们通过继承Session/persistence context来封装一个长会话流程的时候，一个persist这样的函数是需要的。<br />
<br />
3.save"不保证"第2条，它要返回标识符，所以它会立即执行Sql insert，不管是不是在transaction内部。<br />
<br />
五、saveOrUpdateCopy，merge和update区别<br />
<br />
首先说明merge是用来代替saveOrUpdateCopy的,然后比较update和merge，update的作用上边说了，这里说一下merge的作用。<br />
<br />
如果session中存在相同持久化标识（identifier）的实例，用用户给出的对象的状态覆盖旧有的持久实例<br />
<br />
如果session没有相应的持久实例，则尝试从数据库中加载，或创建新的持久化实例，最后返回该持久实例<br />
<br />
用户给出的这个对象没有被关联到session上，它依旧是脱管的<br />
<br />
重点是最后一句：<br />
<br />
当我们使用update的时候，执行完成后，我们提供的对象A的状态变成持久化状态<br />
<br />
但当我们使用merge的时候，执行完成，我们提供的对象A还是脱管状态，hibernate或者new了一个B，或者检索到一个持久对象，并把我们提供的对象A的所有的值拷贝到这个B，执行完成后B是持久状态，而我们提供的A还是托管状态。<br />
<br />
六、flush和update区别<br />
<br />
这两个的区别好理解<br />
<br />
update操作的是在脱管状态的对象，而flush是操作的在持久状态的对象。<br />
<br />
默认情况下，一个持久状态的对象是不需要update的，只要你更改了对象的值，等待hibernate flush就自动保存到数据库了。hibernate flush发生再几种情况下：<br />
<br />
1.调用某些查询的时候<br />
<br />
2.transaction commit的时候<br />
<br />
3.手动调用flush的时候<br />
<br />
七、lock和update区别<br />
<br />
update是把一个已经更改过的脱管状态的对象变成持久状态<br />
<br />
lock是把一个没有更改过的脱管状态的对象变成持久状态<br />
<br />
对应更改一个记录的内容，两个的操作不同：<br />
<br />
update的操作步骤是：<br />
<br />
更改脱管的对象-&gt;调用update<br />
<br />
lock的操作步骤是：<br />
<br />
调用lock把对象从脱管状态变成持久状态——&gt;更改持久状态的对象的内容——&gt;等待flush或者手动flush<br />
<br />
<br />
<img src ="http://www.blogjava.net/sutao/aggbug/158756.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-11-07 10:54 <a href="http://www.blogjava.net/sutao/articles/158756.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>proxy-lazy机制</title><link>http://www.blogjava.net/sutao/articles/144546.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Wed, 12 Sep 2007 09:15:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/144546.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/144546.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/144546.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/144546.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/144546.html</trackback:ping><description><![CDATA[<span style="color: #3c20ff;"><span style="color: #3c20ff;"><span style="color: #3c20ff;"><span style="color: #3c20ff;"><span style="color: #3c20ff;"><span style="color: #3518ff;"><span style="color: #3c20ff;"><strong style="color: black; background-color: #ffff66;">ld</strong> <strong style="color: black; background-color: #a0ffff;">not</strong> <strong style="color: black; background-color: #99ff99;">initialize</strong> <strong style="color: black; background-color: #ff9999;">proxy</strong> <strong style="color: black; background-color: #ff66ff;">-</strong> <strong style="color: white; background-color: #880000;">the</strong> <strong style="color: white; background-color: #00aa00;">owning</strong> <strong style="color: white; background-color: #886800;">Session</strong> <strong style="color: white; background-color: #004699;">was</strong> <strong style="color: white; background-color: #990099;">closed</strong> (篇幅一)
<div>2007<strong style="color: black; background-color: #ff66ff;">-</strong>05<strong style="color: black; background-color: #ff66ff;">-</strong>11  09:52</div>
<table style="table-layout: fixed;">
    <tbody>
        <tr>
            <td>
            <div>
            <p>其实这个异常写的非常之清楚，就是会话关闭，无法对Hibernate实体进行操作。造成这样的情况有很多，什么书写错误啊，逻辑错误啊。</p>
            <p>但就此说一下关于lazy机制：</p>
            <p><font color="#800080">延迟初始化错误是运用Hibernate开发项目时最常见的错误。如果对一个类或者集合配置了延迟检索策略，那么必须当代理类实例或代理集合处于持久化状态（即处于</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">Session</strong></strong><font color="#800080">范围内）时，才能初始化它。如果在游离状态时才初始化它，就会产生延迟初始化错误。<br />
            <br />
            下面把Customer.hbm.xml文件的&lt;class&gt;元素的lazy属性设为true，表示使用延迟检索策略：<br />
            <br />
            &lt;class name="mypack.Customer" table="CUSTOMERS" lazy="true"&gt;<br />
            <br />
            当执行</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">Session</strong></strong><font color="#800080">的load()方法时，Hibernate不会立即执行查询CUSTOMERS表的select语句，仅仅返回Customer类的代理类的实例，这个代理类具由以下特征：<br />
            <br />
            （1） 由Hibernate在运行时动态生成，它扩展了Customer类，因此它继承了Customer类的所有属性和方法，但它的实现对于应用程序是透明的。<br />
            （2） 当Hibernate创建Customer代理类实例时，仅仅初始化了它的OID属性，其他属性都为null，因此这个代理类实例占用的内存很少。<br />
            （3）当应用程序第一次访问Customer代理类实例时（例如调用customer.getXXX()或customer.setXXX()方法），
            Hibernate会初始化代理类实例，在初始化过程中执行select语句，真正从数据库中加载Customer对象的所有数据。但有个例外，那就是当
            应用程序访问Customer代理类实例的getId()方法时，Hibernate不会初始化代理类实例，因为在创建代理类实例时OID就存在了，不必
            到数据库中去查询。<br />
            <br />
            提示：Hibernate采用CGLIB工具来生成持久化类的代理类。CGLIB是一个功能强大的Java字节码生成工具，它能够在程序运行时动态生成扩
            展 Java类或者实现Java接口的代理类。关于CGLIB的更多知识，请参考：http://cglib.sourceforge.net/。<br />
            <br />
            以下代码先通过</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">Session</strong></strong><font color="#800080">的load()方法加载Customer对象，然后访问它的name属性： <br />
            <br />
            tx = </font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">session</strong></strong><font color="#800080">.beginTransaction();<br />
            Customer customer=(Customer)</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">session</strong></strong><font color="#800080">.load(Customer.class,new Long(1));<br />
            customer.getName();<br />
            tx.commit();<br />
            <br />
            在运行</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">session</strong></strong><font color="#800080">.load
            ()方法时Hibernate不执行任何select语句，仅仅返回Customer类的代理类的实例，它的OID为1，这是由load()方法的第二个
            参数指定的。当应用程序调用customer.getName()方法时，Hibernate会初始化Customer代理类实例，从数据库中加载
            Customer对象的数据，执行以下select语句：<br />
            <br />
            select * from CUSTOMERS where ID=1;<br />
            select * from ORDERS where CUSTOMER_ID=1;<br />
            <br />
            当&lt;class&gt;元素的lazy属性为true，会影响</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">Session</strong></strong><font color="#800080">的load()方法的各种运行时行为，下面举例说明。<br />
            <br />
            1．如果加载的Customer对象在数据库中不存在，</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">Session</strong></strong><font color="#800080">的load()方法不会抛出异常，只有当运行customer.getName()方法时才会抛出以下异常：<br />
            <br />
            ERROR LazyInitializer:63 </font><strong style="color: black; background-color: #ff66ff;"><strong style="color: black; background-color: #ff66ff;">-</strong></strong><font color="#800080"> Exception initializing </font><strong style="color: black; background-color: #ff9999;"><strong style="color: black; background-color: #ff9999;">proxy</strong></strong><br />
            <font color="#800080">net.sf.hibernate.ObjectNotFoundException: No row with </font><strong style="color: white; background-color: #880000;"><strong style="color: white; background-color: #880000;">the</strong></strong><font color="#800080"> given identifier exists: 1, of class: <br />
            mypack.Customer<br />
            <br />
            2．如果在整个</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">Session</strong></strong><font color="#800080">范围内，应用程序没有访问过Customer对象，那么Customer代理类的实例一直不会被初始化，Hibernate不会执行任何select语句。以下代码试图在关闭</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">Session</strong></strong><font color="#800080">后访问Customer游离对象：<br />
            <br />
            tx = </font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">session</strong></strong><font color="#800080">.beginTransaction();<br />
            Customer customer=(Customer)</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">session</strong></strong><font color="#800080">.load(Customer.class,new Long(1));<br />
            tx.commit();<br />
            </font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">session</strong></strong><font color="#800080">.close();<br />
            customer.getName();<br />
            <br />
            由于引用变量customer引用的Customer代理类的实例在</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">Session</strong></strong><font color="#800080">范围内始终没有被初始化，因此在执行customer.getName()方法时，Hibernate会抛出以下异常：<br />
            <br />
            ERROR LazyInitializer:63 </font><strong style="color: black; background-color: #ff66ff;"><strong style="color: black; background-color: #ff66ff;">-</strong></strong><font color="#800080"> Exception initializing </font><strong style="color: black; background-color: #ff9999;"><strong style="color: black; background-color: #ff9999;">proxy</strong></strong><br />
            <font color="#800080">net.sf.hibernate.HibernateException: </font><strong style="color: black; background-color: #ffff66;"><strong style="color: black; background-color: #ffff66;">Could</strong></strong><strong style="color: black; background-color: #a0ffff;"><strong style="color: black; background-color: #a0ffff;">not</strong></strong><strong style="color: black; background-color: #99ff99;"><strong style="color: black; background-color: #99ff99;">initialize</strong></strong><strong style="color: black; background-color: #ff9999;"><strong style="color: black; background-color: #ff9999;">proxy</strong></strong><strong style="color: black; background-color: #ff66ff;"><strong style="color: black; background-color: #ff66ff;">-</strong></strong><strong style="color: white; background-color: #880000;"><strong style="color: white; background-color: #880000;">the</strong></strong><strong style="color: white; background-color: #00aa00;"><strong style="color: white; background-color: #00aa00;">owning</strong></strong><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">Session</strong></strong><strong style="color: white; background-color: #004699;"><strong style="color: white; background-color: #004699;">was</strong></strong><strong style="color: white; background-color: #990099;"><strong style="color: white; background-color: #990099;">closed</strong></strong><br />
            <br />
            <font color="#800080">由此可见，Customer代理类的实例只有在当前</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">Session</strong></strong><font color="#800080">范围内才能被初始化。<br />
            <br />
            3．net.sf.hibernate.Hibernate类的</font><strong style="color: black; background-color: #99ff99;"><strong style="color: black; background-color: #99ff99;">initialize</strong></strong><font color="#800080">()静态方法用于在</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">Session</strong></strong><font color="#800080">范围内显式初始化代理类实例，isInitialized()方法用于判断代理类实例是否已经被初始化。例如：<br />
            <br />
            tx = </font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">session</strong></strong><font color="#800080">.beginTransaction();<br />
            Customer customer=(Customer)</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">session</strong></strong><font color="#800080">.load(Customer.class,new Long(1));<br />
            if(!Hibernate.isInitialized(customer)) <br />
            Hibernate.</font><strong style="color: black; background-color: #99ff99;"><strong style="color: black; background-color: #99ff99;">initialize</strong></strong><font color="#800080">(customer);<br />
            tx.commit();<br />
            </font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">session</strong></strong><font color="#800080">.close();<br />
            customer.getName();<br />
            <br />
            以上代码在</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">Session</strong></strong><font color="#800080">范围内通过Hibernate类的</font><strong style="color: black; background-color: #99ff99;"><strong style="color: black; background-color: #99ff99;">initialize</strong></strong><font color="#800080">()方法显式初始化了Customer代理类实例，因此当</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">Session</strong></strong><font color="#800080">关闭后，可以正常访问Customer游离对象。<br />
            <br />
            4．当应用程序访问代理类实例的getId()方法时，不会触发Hibernate初始化代理类实例的行为，例如：<br />
            <br />
            tx = </font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">session</strong></strong><font color="#800080">.beginTransaction();<br />
            Customer customer=(Customer)</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">session</strong></strong><font color="#800080">.load(Customer.class,new Long(1));<br />
            customer.getId();<br />
            tx.commit();<br />
            </font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">session</strong></strong><font color="#800080">.close();<br />
            customer.getName();<br />
            <br />
            当应用程序访问customer.getId()方法时，该方法直接返回Customer代理类实例的OID值，无需查询数据库。由于引用变量 customer始终引用的是没有被初始化的Customer代理类实例，因此当</font><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">Session</strong></strong><font color="#800080">关闭后再执行customer.getName()方法， Hibernate会抛出以下异常：</font></p>
            <p><font color="#800080">ERROR LazyInitializer:63 </font><strong style="color: black; background-color: #ff66ff;"><strong style="color: black; background-color: #ff66ff;">-</strong></strong><font color="#800080"> Exception initializing </font><strong style="color: black; background-color: #ff9999;"><strong style="color: black; background-color: #ff9999;">proxy</strong></strong><br />
            <font color="#800080">net.sf.hibernate.HibernateException: </font><strong style="color: black; background-color: #ffff66;"><strong style="color: black; background-color: #ffff66;">Could</strong></strong><strong style="color: black; background-color: #a0ffff;"><strong style="color: black; background-color: #a0ffff;">not</strong></strong><strong style="color: black; background-color: #99ff99;"><strong style="color: black; background-color: #99ff99;">initialize</strong></strong><strong style="color: black; background-color: #ff9999;"><strong style="color: black; background-color: #ff9999;">proxy</strong></strong><strong style="color: black; background-color: #ff66ff;"><strong style="color: black; background-color: #ff66ff;">-</strong></strong><strong style="color: white; background-color: #880000;"><strong style="color: white; background-color: #880000;">the</strong></strong><strong style="color: white; background-color: #00aa00;"><strong style="color: white; background-color: #00aa00;">owning</strong></strong><strong style="color: white; background-color: #886800;"><strong style="color: white; background-color: #886800;">Session</strong></strong><strong style="color: white; background-color: #004699;"><strong style="color: white; background-color: #004699;">was</strong></strong><strong style="color: white; background-color: #990099;"><strong style="color: white; background-color: #990099;">closed</strong></strong></p>
            <p><strong><font style="background-color: #990099;" color="#ffffff">解决方法：</font></strong></p>
            <p>由于hibernate采用了lazy=true,这样当你用hibernate查询时,返回实际为利用cglib增强的代理类,但其并没有实际填
            充;当你在前端,利用它来取值(getXXX)时,这时Hibernate才会到数据库执行查询,并填充对象,但此时如果和这个代理类相关的<strong style="color: white; background-color: #886800;">session</strong>已关闭掉,就会产生种错误.<br />
            在做一对多时，有时会出现"<strong style="color: black; background-color: #ffff66;">could</strong> <strong style="color: black; background-color: #a0ffff;">not</strong> <strong style="color: black; background-color: #99ff99;">initialize</strong> <strong style="color: black; background-color: #ff9999;">proxy</strong> <strong style="color: black; background-color: #ff66ff;">-</strong> clothe <strong style="color: white; background-color: #00aa00;">owning</strong> <strong style="color: white; background-color: #886800;">Session</strong> <strong style="color: white; background-color: #004699;">was</strong> sed,这个好像是hibernate的缓存问题.问题解决:需要在&lt;many<strong style="color: black; background-color: #ff66ff;">-</strong>to<strong style="color: black; background-color: #ff66ff;">-</strong>one&gt;里设置lazy="false". 但有可能会引发另一个异常叫</p>
            <p>failed to lazily <strong style="color: black; background-color: #99ff99;">initialize</strong> a collection of role: XXXXXXXX, no <strong style="color: white; background-color: #886800;">session</strong> or <strong style="color: white; background-color: #886800;">session</strong> <strong style="color: white; background-color: #004699;">was</strong> <strong style="color: white; background-color: #990099;">closed</strong></p>
            <p>此异常解决方案请察看本人博客（<a href="http://hi.baidu.com/kekemao1">http://hi.baidu.com/kekemao1</a>）的Hibernate异常中的《failed to lazily <strong style="color: black; background-color: #99ff99;">initialize</strong> a collection of role异常》<br />
            <br />
            ?<br />
            解决方法:在web.xml中加入<br />
            &lt;filter&gt;<br />
            &nbsp;&nbsp;&nbsp; &lt;filter<strong style="color: black; background-color: #ff66ff;">-</strong>name&gt;hibernateFilter&lt;/filter<strong style="color: black; background-color: #ff66ff;">-</strong>name&gt;<br />
            &nbsp;&nbsp;&nbsp; &lt;filter<strong style="color: black; background-color: #ff66ff;">-</strong>class&gt;<br />
            &nbsp;&nbsp;&nbsp;&nbsp; org.springframework.orm.hibernate3.support.OpenSessionInViewFilter<br />
            &nbsp;&nbsp;&nbsp; &lt;/filter<strong style="color: black; background-color: #ff66ff;">-</strong>class&gt;<br />
            &lt;/filter<br />
            &lt;filter<strong style="color: black; background-color: #ff66ff;">-</strong>mapping&gt;<br />
            &nbsp;&nbsp;&nbsp; &lt;filter<strong style="color: black; background-color: #ff66ff;">-</strong>name&gt;hibernateFilter&lt;/filter<strong style="color: black; background-color: #ff66ff;">-</strong>name&gt;<br />
            &nbsp;&nbsp;&nbsp; &lt;url<strong style="color: black; background-color: #ff66ff;">-</strong>pattern&gt;*.do&lt;/url<strong style="color: black; background-color: #ff66ff;">-</strong>pattern&gt;<br />
            &lt;/filter<strong style="color: black; background-color: #ff66ff;">-</strong>mapping&gt;<br />
            就可以了;</p>
            <p>参考了:<br />
            Hibernate与延迟加载：</p>
            <p>Hibernate对象关系映射提供延迟的与非延迟的对象初始化。非延迟加载在读取一个对象的时候会将与这个对象所有相关的其他对象一起读取出来。
            这有时会导致成百的（如果不是成千的话）select语句在读取对象的时候执行。这个问题有时出现在使用双向关系的时候，经常会导致整个数据库都在初始化
            的阶段被读出来了。当然，你可以不厌其烦地检查每一个对象与其他对象的关系，并把那些最昂贵的删除，但是到最后，我们可能会因此失去了本想在ORM工具中
            获得的便利。</p>
            <p><br />
            一个明显的解决方法是使用Hibernate提供的延迟加载机制。这种初始化策略只在一个对象调用它的一对多或多对多关系时才将关系对象读取出来。这个过
            程对开发者来说是透明的，而且只进行了很少的数据库操作请求，因此会得到比较明显的性能提升。这项技术的一个缺陷是延迟加载技术要求一个
            Hibernate会话要在对象使用的时候一直开着。这会成为通过使用DAO模式将持久层抽象出来时的一个主要问题。为了将持久化机制完全地抽象出来，所
            有的数据库逻辑，包括打开或关闭会话，都不能在应用层出现。最常见的是，一些实现了简单接口的DAO实现类将数据库逻辑完全封装起来了。一种快速但是笨拙
            的解决方法是放弃DAO模式，将数据库连接逻辑加到应用层中来。这可能对一些小的应用程序有效，但是在大的系统中，这是一个严重的设计缺陷，妨碍了系统的
            可扩展性。</p>
            <p>在Web层进行延迟加载</p>
            <p>幸运的是，Spring框架为Hibernate延迟加载与DAO模式的整合提供了一种方便的解决方法。对那些不熟悉Spring与
            Hibernate集成使用的人，我不会在这里讨论过多的细节，但是我建议你去了解Hibernate与Spring集成的数据访问。以一个Web应用为
            例，Spring提供了OpenSessionInViewFilter和OpenSessionInViewInterceptor。我们可以随意选择
            一个类来实现相同的功能。两种方法唯一的不同就在于interceptor在Spring容器中运行并被配置在web应用的上下文中，而Filter在
            Spring之前运行并被配置在web.xml中。不管用哪个，他们都在请求将当前会话与当前（数据库）线程绑定时打开Hibernate会话。一旦已绑
            定到线程，这个打开了的Hibernate会话可以在DAO实现类中透明地使用。这个会话会为延迟加载数据库中值对象的视图保持打开状态。一旦这个逻辑视
            图完成了，Hibernate会话会在Filter的doFilter方法或者Interceptor的postHandle方法中被关闭。下面是每个组
            件的配置示例：</p>
            <p><br />
            Interceptor的配置:</p>
            <p>&lt;beans&gt; <br />
            &lt;bean id="urlMapping" <br />
            class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"&gt; <br />
            &lt;property name="interceptors"&gt; <br />
            &lt;list&gt; <br />
            &lt;ref bean="openSessionInViewInterceptor"/&gt; <br />
            &lt;/list&gt; <br />
            &lt;/property&gt; <br />
            &lt;property name="mappings"&gt; <br />
            <br />
            &lt;/bean&gt; <br />
            <br />
            &lt;bean name="openSessionInViewInterceptor" <br />
            class="org.springframework.orm.hibernate.support.OpenSessionInViewInterceptor"&gt; <br />
            &lt;property name="sessionFactory"&gt;&lt;ref bean="sessionFactory"/&gt;&lt;/property&gt; <br />
            &lt;/bean&gt; <br />
            &lt;/beans&gt; </p>
            <p>Filter的配置</p>
            <p>&lt;web<strong style="color: black; background-color: #ff66ff;">-</strong>app&gt; <br />
            <br />
            &lt;filter&gt; <br />
            &lt;filter<strong style="color: black; background-color: #ff66ff;">-</strong>name&gt;hibernateFilter&lt;/filter<strong style="color: black; background-color: #ff66ff;">-</strong>name&gt; <br />
            &lt;filter<strong style="color: black; background-color: #ff66ff;">-</strong>class&gt; <br />
            org.springframework.orm.hibernate.support.OpenSessionInViewFilter <br />
            &lt;/filter<strong style="color: black; background-color: #ff66ff;">-</strong>class&gt; <br />
            &lt;/filter&gt; <br />
            <br />
            &lt;filter<strong style="color: black; background-color: #ff66ff;">-</strong>mapping&gt; <br />
            &lt;filter<strong style="color: black; background-color: #ff66ff;">-</strong>name&gt;hibernateFilter&lt;/filter<strong style="color: black; background-color: #ff66ff;">-</strong>name&gt; <br />
            &lt;url<strong style="color: black; background-color: #ff66ff;">-</strong>pattern&gt;*. spring &lt;/url<strong style="color: black; background-color: #ff66ff;">-</strong>pattern&gt; <br />
            &lt;/filter<strong style="color: black; background-color: #ff66ff;">-</strong>mapping&gt; <br />
            <br />
            &lt;/web<strong style="color: black; background-color: #ff66ff;">-</strong>app&gt; </p>
            <p><br />
            实现Hibernate的Dao接口来使用打开的会话是很容易的。事实上，如果你已经使用了Spring框架来实现你的Hibernate
            Dao,很可能你不需要改变任何东西。方便的HibernateTemplate公用组件使访问数据库变成小菜一碟，而DAO接口只有通过这个组件才可以
            访问到数据库。下面是一个示例的DAO：</p>
            <p><br />
            public class HibernateProductDAO extends HibernateDaoSupport implements ProductDAO { </p>
            <p>public Product getProduct(Integer productId) { <br />
            return (Product)getHibernateTemplate().load(Product.class, productId); <br />
            } </p>
            <p>public Integer saveProduct(Product product) { <br />
            return (Integer) getHibernateTemplate().save(product); <br />
            } </p>
            <p>public void updateProduct(Product product) { <br />
            getHibernateTemplate().update(product); <br />
            } <br />
            } </p>
            <p>在业务逻辑层中使用延迟加载</p>
            <p>即使在视图外面，Spring框架也通过使用AOP 拦截器
            HibernateInterceptor来使得延迟加载变得很容易实现。这个Hibernate
            拦截器透明地将调用配置在Spring应用程序上下文中的业务对象中方法的请求拦截下来，在调用方法之前打开一个Hibernate会话，然后在方法执行
            完之后将会话关闭。让我们来看一个简单的例子，假设我们有一个接口BussinessObject：</p>
            <p><br />
            public&nbsp;&nbsp;&nbsp;&nbsp; interface&nbsp;&nbsp;&nbsp; BusinessObject&nbsp;&nbsp;&nbsp;&nbsp; { <br />
            public&nbsp;&nbsp;&nbsp;&nbsp; void&nbsp;&nbsp;&nbsp; doSomethingThatInvolvesDaos(); <br />
            } <br />
            类BusinessObjectImpl实现了BusinessObject接口:</p>
            <p>public&nbsp;&nbsp;&nbsp;&nbsp; class&nbsp;&nbsp;&nbsp; BusinessObjectImpl&nbsp;&nbsp;&nbsp; implements&nbsp;&nbsp;&nbsp; BusinessObject&nbsp;&nbsp;&nbsp;&nbsp; { <br />
            public&nbsp;&nbsp;&nbsp;&nbsp; void&nbsp;&nbsp;&nbsp; doSomethingThatInvolvesDaos()&nbsp;&nbsp;&nbsp;&nbsp; { <br />
            //&nbsp;&nbsp;&nbsp; lots of logic that calls <br />
            //&nbsp;&nbsp;&nbsp; DAO classes Which access <br />
            //&nbsp;&nbsp;&nbsp; data objects lazily&nbsp;&nbsp;<br />
            }&nbsp;&nbsp;<br />
            }&nbsp;&nbsp;</p>
            <p><br />
            通过在Spring应用程序上下文中的一些配置，我们可以让将调用BusinessObject的方法拦截下来，再令它的方法支持延迟加载。看看下面的一个程序片段：</p>
            <p><br />
            &lt;beans&gt; <br />
            &lt;bean id="hibernateInterceptor" class="org.springframework.orm.hibernate.HibernateInterceptor"&gt; <br />
            &lt;property name="sessionFactory"&gt; <br />
            &lt;ref bean="sessionFactory"/&gt; <br />
            &lt;/property&gt; <br />
            &lt;/bean&gt; <br />
            &lt;bean id="businessObjectTarget" class="com.acompany.BusinessObjectImpl"&gt; <br />
            &lt;property name="someDAO"&gt;&lt;ref bean="someDAO"/&gt;&lt;/property&gt; <br />
            &lt;/bean&gt; <br />
            &lt;bean id="businessObject" class="org.springframework.aop.framework.ProxyFactoryBean"&gt; <br />
            &lt;property name="target"&gt;&lt;ref bean="businessObjectTarget"/&gt;&lt;/property&gt; <br />
            &lt;property name="proxyInterfaces"&gt; <br />
            &lt;value&gt;com.acompany.BusinessObject&lt;/value&gt; <br />
            &lt;/property&gt; <br />
            &lt;property name="interceptorNames"&gt; <br />
            &lt;list&gt; <br />
            &lt;value&gt;hibernateInterceptor&lt;/value&gt; <br />
            &lt;/list&gt; <br />
            &lt;/property&gt; <br />
            &lt;/bean&gt; <br />
            &lt;/beans&gt;</p>
            <p>当businessObject被调用的时候，HibernateInterceptor打开一个Hibernate会话，并将调用请求传递给
            BusinessObjectImpl对象。当BusinessObjectImpl执行完成后，HibernateInterceptor透明地关闭了
            会话。应用层的代码不用了解任何持久层逻辑，还是实现了延迟加载。</p>
            <p><br />
            在单元测试中测试延迟加载</p>
            <p>最后，我们需要用J<strong style="color: black; background-color: #ff66ff;">-</strong>Unit来测试我们的延迟加载程序。我们可以轻易地通过重写TestCase类中的setUp和tearDown方法来实现这个要求。我比较喜欢用这个方便的抽象类作为我所有测试类的基类。</p>
            <p><br />
            public abstract class MyLazyTestCase extends TestCase { </p>
            <p>private SessionFactory sessionFactory; <br />
            private <strong style="color: white; background-color: #886800;">Session</strong> <strong style="color: white; background-color: #886800;">session</strong>; </p>
            <p>public void setUp() throws Exception { <br />
            super.setUp(); <br />
            SessionFactory sessionFactory = (SessionFactory) getBean("sessionFactory"); <br />
            <strong style="color: white; background-color: #886800;">session</strong> = SessionFactoryUtils.getSession(sessionFactory, true); <br />
            <strong style="color: white; background-color: #886800;">Session</strong> s = sessionFactory.openSession(); <br />
            TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(s)); </p>
            <p>} </p>
            <p>protected Object getBean(String beanName) { <br />
            //Code to get objects from Spring application context <br />
            } </p>
            <p>public void tearDown() throws Exception { <br />
            super.tearDown(); <br />
            SessionHolder holder = (SessionHolder) TransactionSynchronizationManager.getResource(sessionFactory); <br />
            <strong style="color: white; background-color: #886800;">Session</strong> s = holder.getSession(); <br />
            s.flush(); <br />
            TransactionSynchronizationManager.unbindResource(sessionFactory); <br />
            SessionFactoryUtils.closeSessionIfNecessary(s, sessionFactory); <br />
            } <br />
            }</p>
            <p><br />
            </p>
            </div>
            </td>
        </tr>
    </tbody>
</table>
</span></span></span></span></span></span></span>
<img src ="http://www.blogjava.net/sutao/aggbug/144546.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-09-12 17:15 <a href="http://www.blogjava.net/sutao/articles/144546.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>测试 hibernate 性能 驱动 jdbc 数据库 版本 数据  </title><link>http://www.blogjava.net/sutao/articles/138675.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Wed, 22 Aug 2007 10:45:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/138675.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/138675.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/138675.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/138675.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/138675.html</trackback:ping><description><![CDATA[<br style="color: #101fff;">
<br style="color: #101fff;"><span style="color: #101fff;">
lifejoy网友写了段测试程序，用Hibernate作为持久手段测试了大数据量写入MySql数据库的性能。程序主要使用了一个循环嵌套，最里层循
环为批量插入记录的代码，每一批插1000条记录，最外层循环为批次的控制，一共循环100批次，这样总的数据写入量为1000x100共十万记录。从
lifejoy的测试数据看，用JDBC直接写的速率是600-800条/秒，而用Hibernate写的速率会从一开始的300多条降至几十条每秒，这
个差距非常之大，难怪lifejoy使用了&#8220;暴差&#8221;这一非常使人触目惊心的语言。 </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">Hibernate
的写入性能到底如何？真的到了&#8220;暴差&#8221;这样的地步么？其性能与JDBC直写相比，到底差距多大？这些个问题，通过google
结果，众说纷纭，莫衷一是，在台湾JavaWorld论坛上，有网友贴出了Hibernate比JDBC性能更加优越的测试结果分析图，也有很多网友在诟
病Hibernate在ORM的同时丧失了性能，到底真相在何方？由于今年做了一个基于Oracle的大型系统，需要支撑高并发数据访问量，在决定系统架
构的时候，首席架构师选择了iBatis，而放弃了Hibernate，其中一个最大的考虑就是这个性能因素，可惜当初没有进行技术实际论证，于是有了今
天的这个&#8220;考&#8221;，打算通过实际测试结果来验证一下Hibernate的性能情况，以澄清如下问题： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> &lt;!--[if !supportLists]--&gt;1.         &lt;!--[endif]--&gt;Hibernate ORM读写与JDBC方式读写在性能上孰优孰劣？ </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> &lt;!--[if !supportLists]--&gt;2.         &lt;!--[endif]--&gt;优势多少？劣势又是几何？ </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 依照lifejoy的思路下写以下一段代码： </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> package com.gmail.newmanhuang.learnhibernate; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> import java.util.Iterator; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> import java.util.List; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> import org.hibernate.SessionFactory; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> import org.hibernate.Session; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> import org.hibernate.Transaction; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> import org.hibernate.cfg.Configuration; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> import org.hibernate.Criteria; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> import org.hibernate.criterion.Expression; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> import com.gmail.newmanhuang.learnhibernate.model.Person; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> import java.sql.*; </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> public class LearnHibernateMain { </span><br style="color: #101fff;">  <br style="color: #101fff;">         <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        private Configuration config; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        private SessionFactory sessionFactory; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        private Session session; </span><br style="color: #101fff;">  <br style="color: #101fff;">         <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        public static void main(String[] args) { </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               LearnHibernateMain lh=new LearnHibernateMain(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               //用hibernate创建10000条记录，分10次插入，每次1000条，每100条记录做一次批量插入 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               //lh.createPersons(10, 1000, 100); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               //用jdbc直接创建10000条记录，分10次插入，每次1000条，每100条记录做一次批量插入 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               lh.createPersonsByJDBC(10, 1000,100); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        } </span><br style="color: #101fff;">  <br style="color: #101fff;">         <br style="color: #101fff;">  <br style="color: #101fff;">         <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        //用hibernate创建person记录, loopNum为循环插入的次数，batchNum1为每次循环插入的记录数，batchNum2为物理批量插入记录数 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        private void createPersons(int loopNum,int batchNum1,int batchNum2){ </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               setup(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               System.out.println("hibernate record creating testing.\r\n"  </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             + "loop times:" + loopNum + "\r\nbatch number:" + batchNum1); </span><br style="color: #101fff;">  <br style="color: #101fff;">                <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               for(int i=0;i&lt;loopNum;i++){ </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      try { </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             Thread.sleep(50);//休眠 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      } catch (InterruptedException e) { </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             e.printStackTrace(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      } </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      long fPoint=System.currentTimeMillis(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      Transaction tx = session.beginTransaction(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      for(int j=0;j&lt;batchNum1;j++){ </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             Person person = new Person(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             person.setName("name-" + i +"-"+ j); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             person.setAge(new Integer(25)); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             session.save(person); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             //batch flush </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             if ( j % batchNum2 == 0 ) {//执行物理批量插入 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                                    session.flush();  </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                                    session.clear();              </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             } </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      } </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      tx.commit(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      long tPoint=System.currentTimeMillis(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      //打印插入batchNum1条记录的速率(条/秒) </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      System.out.println( </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                                    "the " + i + " batch" + "(" + batchNum1 +") rcds/s:"  </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                                    + ((double)batchNum1/(tPoint-fPoint))*1000); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               } </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               teardown(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        } </span><br style="color: #101fff;">  <br style="color: #101fff;">         <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        //用jdbc创建person记录, loopNum为循环插入的次数，batchNum1为每次循环插入的记录数，batchNum2为物理批量插入记录数 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        private void createPersonsByJDBC(int loopNum,int batchNum1,int batchNum2){ </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               System.out.println("JDBC record creating testing.\r\n"  </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             + "loop times:" + loopNum + "\r\nbatch number:" + batchNum1); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               Connection conn=getDBConn(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               try{ </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      PreparedStatement pstmt=conn.prepareStatement("insert into person(name,age) values(?,?)"); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      for(int i=0;i&lt;loopNum;i++){ </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             try { </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                                    Thread.sleep(50);//休眠 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             } catch (InterruptedException e) { </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                                    e.printStackTrace(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             } </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             long fPoint=System.currentTimeMillis(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             conn.setAutoCommit(false); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             for(int j=0;j&lt;batchNum1;j++){ </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                                    String name="name-" + i +"-"+ j; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                                    pstmt.setString(1, name); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                                    pstmt.setInt(2, 25); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                                    pstmt.addBatch(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                                    if(j%batchNum2==0){//执行物理批量插入 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                                           pstmt.executeBatch(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                                           conn.commit(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                                    } </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             } </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             pstmt.executeBatch(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             conn.commit(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             conn.setAutoCommit(true); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             long tPoint=System.currentTimeMillis(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             //打印插入batchNum1条记录的速率(条/秒) </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             System.out.println( </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                                           "the " + i + " batch" + "(" + batchNum1 +") rcds/s:"  </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                                           + ((double)batchNum1/(tPoint-fPoint))*1000); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      } </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      pstmt.close(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               }catch(Exception x){ </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      try{ </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                             conn.close(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      }catch(Exception x1){ </span><br style="color: #101fff;">  <br style="color: #101fff;">                              <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      } </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               } </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        } </span><br style="color: #101fff;">  <br style="color: #101fff;">         <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        //获取JDBC连接 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        private Connection getDBConn(){ </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               Connection conn=null; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               try { </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      Class.forName("org.gjt.mm.mysql.Driver"); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">                      conn=DriverManager.getConnection("jdbc:mysql://localhost/learnhibernate", "root", ""); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               } catch (Exception x) { </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               } </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               return conn; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        } </span><br style="color: #101fff;">  <br style="color: #101fff;">         <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        //初始化hibernate数据库环境 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        private void setup(){ </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               config = new Configuration().configure(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               sessionFactory = config.buildSessionFactory(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               session = sessionFactory.openSession(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        } </span><br style="color: #101fff;">  <br style="color: #101fff;">         <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        //销毁hibernate数据库环境 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        private void teardown(){ </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               session.close(); </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">               sessionFactory.close();          </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">        } </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> } </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">测
试环境主要为：J2SDK1.4.2_04, MySql4.1.9-Max, Hibernate3.1, IBM Thinkpad R32-P4
1.8G, 512M
Memory；MySql中待插表的类型为INNODB，以支持事务，ISAM类型表的读写速率要远高于INNODB，这里不采用ISAM是因为不支持事
务。 </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 主要分为三个测试场景，以下为三个场景的测试记录和分析： </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 测试场景一： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ############# 测试环境一 ####################### </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> mysql版本：4.1.9-max </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> jdbc驱动：mysql-connector-java-3.1.11-bin.jar </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> hibernate: 3.1 </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ################################################ </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 1.hibernate批量插入，创建10000条记录，分10次插入，每次1000条，每100条记录做一次批量插入操作 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 测试记录： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ====================================================================== </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> hibernate record creating testing. </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> loop times:10 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> batch number:1000 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 0 batch(1000) rcds/s:172.1763085399449 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 1 batch(1000) rcds/s:214.73051320592657 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 2 batch(1000) rcds/s:302.6634382566586 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 3 batch(1000) rcds/s:321.13037893384717 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 4 batch(1000) rcds/s:318.9792663476874 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 5 batch(1000) rcds/s:316.05562579013906 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 6 batch(1000) rcds/s:318.9792663476874 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 7 batch(1000) rcds/s:317.05770450221945 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 8 batch(1000) rcds/s:317.9650238473768 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 9 batch(1000) rcds/s:314.96062992125985 </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 测试结果： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> hibernate新记录创建平均速率：~290条/秒 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ====================================================================== </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 2.jdbc批量插入，创建10000条记录，分10次插入，每次1000条，每100条记录做一次批量插入操作 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 测试记录： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ====================================================================== </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> JDBC record creating testing. </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> loop times:10 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> batch number:1000 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 0 batch(1000) rcds/s:812.3476848090983 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 1 batch(1000) rcds/s:988.1422924901185 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 2 batch(1000) rcds/s:1233.0456226880394 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 3 batch(1000) rcds/s:1314.060446780552 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 4 batch(1000) rcds/s:1201.923076923077 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 5 batch(1000) rcds/s:1349.527665317139 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 6 batch(1000) rcds/s:853.9709649871904 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 7 batch(1000) rcds/s:1218.026796589525 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 8 batch(1000) rcds/s:1175.0881316098707 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 9 batch(1000) rcds/s:1331.5579227696405 </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 测试结果： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> jdbc新记录创建平均速率：~1147条/秒 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ====================================================================== </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ******测试环境一结论：jdbc性能明显优于hibernate，写入速率比jdbc/hibernate=3.95 </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 测试场景二： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ############# 测试环境二 ####################### </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> mysql版本：4.1.9-max </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> jdbc驱动：mysql-connector-java-3.0.11-bin.jar（注意这里更换了mysql的connectorJ驱动！！！） </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> hibernate: 3.1 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ################################################ </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 1.hibernate批量插入，创建10000条记录，分10次插入，每次1000条，每100条记录做一次批量插入操作 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 测试记录： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ======================================================================hibernate record creating testing. </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> loop times:10 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> batch number:1000 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 0 batch(1000) rcds/s:536.7686527106817 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 1 batch(1000) rcds/s:504.28643469490675 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 2 batch(1000) rcds/s:1062.6992561105205 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 3 batch(1000) rcds/s:1122.334455667789 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 4 batch(1000) rcds/s:1133.7868480725624 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 5 batch(1000) rcds/s:1122.334455667789 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 6 batch(1000) rcds/s:1008.0645161290322 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 7 batch(1000) rcds/s:1085.7763300760043 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 8 batch(1000) rcds/s:1074.1138560687434 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 9 batch(1000) rcds/s:1096.4912280701756 </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 测试结果： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 新记录创建平均速率：~974条/秒 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ====================================================================== </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 2.jdbc批量插入，创建10000条记录，分10次插入，每次1000条，每100条记录做一次批量插入操作 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 测试记录： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ====================================================================== </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> JDBC record creating testing. </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> loop times:10 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> batch number:1000 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 0 batch(1000) rcds/s:1231.527093596059 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 1 batch(1000) rcds/s:1406.4697609001407 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 2 batch(1000) rcds/s:2000.0 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 3 batch(1000) rcds/s:1692.047377326565 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 4 batch(1000) rcds/s:1386.9625520110958 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 5 batch(1000) rcds/s:1349.527665317139 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 6 batch(1000) rcds/s:1074.1138560687434 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 7 batch(1000) rcds/s:1386.9625520110958 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 8 batch(1000) rcds/s:1636.6612111292961 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 9 batch(1000) rcds/s:1814.8820326678765 </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 测试结果： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 新记录创建平均速率：~1497条/秒 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ====================================================================== </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ******测试环境二结论：jdbc性能仍优于hibernate，写入速率比jdbc/hibernate =1.58 </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 测试场景三： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ############# 测试环境三 ####################### </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> mysql版本：4.1.9-max </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> jdbc驱动：mysql-connector-java-3.0.11-bin.jar（与测试环境二使用同样的驱动） </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> hibernate: 3.1 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 特别说明：记录插入不使用事务 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ################################################ </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 1.jdbc批量插入，创建10000条记录，分10次插入，每次1000条，每100条记录做一次批量插入操作，不使用事务（注意这里，不使用事务！！） </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 测试记录： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> =========================================================================================== </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> JDBC record creating testing. </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> loop times:10 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> batch number:1000 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 0 batch(1000) rcds/s:43.11645755184754 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 1 batch(1000) rcds/s:34.32651379925854 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 2 batch(1000) rcds/s:40.65701740120345 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 3 batch(1000) rcds/s:62.44925997626928 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 4 batch(1000) rcds/s:69.58942240779402 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 5 batch(1000) rcds/s:42.45743641998896 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 6 batch(1000) rcds/s:44.420753375977256 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 7 batch(1000) rcds/s:44.44049417829527 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 8 batch(1000) rcds/s:56.63797009515179 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> the 9 batch(1000) rcds/s:71.73601147776183 </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 测试结果： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 新记录创建平均速率：~50条/秒 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> ====================================================================== </span><br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 测试结果分析： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 1. 在同等测试环境和条件下，hibernate优于jdbc这种说法是错误的，从测试结果来看， jdbc要优于hibernate，这从理论上是可以理解的，hibernate的基础就是jdbc，它不可能优于jdbc。 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 2. 影响数据库操作性能的因素很多，主要包括： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 1)数据库自身 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 如mysql表类型，是ISAM还是innodb </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 2)数据库驱动 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">从
测试数据和结果看，mysql的3.0.11版本的驱动显然更适合于mysql4.1.9版本的数据库，而高版本的3.1.11用于
hibernate的插入操作则会丧失近3.5倍的执行效率，另外，经过笔者测试，在3.1.11版本的驱动中，使用与不使用批次(batch)插入操作
居然没有任何区别，这也能解释一些技术论坛上提到的hibernate批处理操作有时候会实效这个令人困惑的问题。 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 3)操作数据库的程序本身 </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 测试环境3表明，当mysql的表类型为innodb时，即使是采用JDBC直接写的方式，不采用事务方式插入记录，写入速率几乎是&#8220;蜗速&#8221;（~50条/秒），这可以说是&#8220;杀手级&#8221;的因素了。 </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 结论： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> &lt;!--[if !supportLists]--&gt;1. 笔者估计在大数据量写入状况下，Hibernate的性能损失在30%-35%左右&lt;!--[endif]--&gt; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> &lt;!--[if !supportLists]--&gt;2.  对于要获取高性能数据读写的系统，不推荐使用Hibernate的ORM方式进行数据读写。&lt;!--[endif]--&gt; </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">&lt;!--[if
!supportLists]--&gt;3.
性能的优劣除了所采用的技术决定外，更取决于使用技术的人，比如在测试环境三中，不采用事务方式写数据，其速度简直不能以&#8220;暴差&#8221;来形容，想想这样一种情
况，让你去开一辆法拉利F1赛车，你一定能想象得到你驾驶的速度。：）&lt;!--[endif]--&gt; </span><br style="color: #101fff;">  <br style="color: #101fff;">   <br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;"> 后记： </span><br style="color: #101fff;">  <br style="color: #101fff;"><span style="color: #101fff;">在
进行测试的时候，起初笔者使用的JDBC驱动是J/Conncector
3.1.11版本，发现Hibernate的批量写设置根本不起作用，是否使用批量写根本就没有差别，在一些网站上面也发现有类似的疑问，经过更换为
3.0.x版本驱动后，批量写才生效，而且无论是Hibernate方式还是JDBC方式下，写记录的性能明显提升，表明3.0.X的驱动更适合于
MySql4.1，为什么高版本的3.1.11反而在低版本数据库上面表现出低效？笔者在安装Roller这个Apache孵化器blog项目的时候，也
对安装指导中推荐使用3.0.X版本来匹配MySql4.1数据库这个问题比较疑惑，可惜Roller的InstallGuid没有做具体解释，感兴趣的
网友可以到Roller网站的wiki上去弄清楚这个问题，并把答案做个回复，非常感谢。这个插曲还说明了一个道理——&#8220;升级并非总是好事&#8221;。</span><br style="color: #101fff;"><br style="color: #101fff;">
<p style="color: #101fff;" id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1339954</p>
<br><img src ="http://www.blogjava.net/sutao/aggbug/138675.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-08-22 18:45 <a href="http://www.blogjava.net/sutao/articles/138675.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate 要点</title><link>http://www.blogjava.net/sutao/articles/134892.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Tue, 07 Aug 2007 02:58:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/134892.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/134892.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/134892.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/134892.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/134892.html</trackback:ping><description><![CDATA[<div id="guestPanel" class=""><a class="textIcon" target="_blank" href="http://blog.sina.com.cn/member/signup/reg_step1.php">注册</a>┆<a target="systemIframe" class="textIcon" title="" href="http://my.blog.sina.com.cn/login/login_top.php" id="login">登录</a>┆<a target="_blank" href="http://blog.sina.com.cn/control/writing/scriber/article_add.php?mode=1" class="textIcon" id="newArticle">发表文章</a> </div>
&nbsp;
<div id="articleBar" class="toggleLink" toggle="articleContentArea">
<a id="toggleButton" class="icon collapsearraw center" href="javascript:void(0)">&nbsp;</a>
<!--class name of articleTime specify 'sun' icon or 'moon' icon
in front of date-time text. Corresponding to class name 'sun' & 'moon'
-->
<a href="javascript:void(0)" id="articleTitle">Hibernate&nbsp;要点</a>
<div id="articleBarButton">
<a id="edit" class="Link icon modify center invisible" href="javascript:void(0)">&nbsp;</a>
<a id="delete" class="Link icon delete center invisible" href="javascript:void(0)">&nbsp;</a>
</div>
</div>
<div id="articleTimeHolder">
2007-02-05 23:10:55
</div>
<div id="articleContentFontSize">
<a href="javascript: void(0);" onclick="setArticleContentSize('b')">大</a>
<a href="javascript: void(0);" onclick="setArticleContentSize('m')" )="">中</a>
<a href="javascript: void(0);" onclick="setArticleContentSize('s')" )="">小</a>
</div>
<div id="tagsArea">
</div>
<div>属性<br>
1&nbsp;
unsaved-value:对级联对象进行数据保存时，Hibernate将根据这个值来判断对象是否需要保存；先从级联对象中取出id，如果id和
unsave-value值相等，则认为对象尚未保存，否则认为对象已经保存（这里的保存指的是insert，而不是update）<br>
;在隐式保存的情况下，Hibernate用目标对象的id值和此值比较，如果相等则insert，否则不insert<br>
2&nbsp;
hbm.xml文件的class标签中有一个polymorphism＝"explicit"属性，它的作用是：声明一个显式多态关系，声明为显式多态的类只有在代码中（如:list
object=createQuery("from
TuserProfile").list();这里显式指明了TuserProfile类）明确指定类名的时候才会返回此类实例;<br>
&nbsp;
如果要返回对应整个数据库中所有库表记录的数据对象，可用: List
obj=createQuery("from
object").list();但不会返回在映射文件中具有polymorphism＝"explicit"定义的类的实例<br>
3
inverse:用于在设置双向一对多关系时设置维护两个实体关系的一方,inverse=false的一方负责维护双方关系;在one-to-many关系中，常将many一方设为false方<br>
4
cascade:指的是当主控方执行操作时，关联对象（被动方）是否同步执行同一操作。例如对主控对象调用save-update或delete方法时，
是否同时对关联对象（被动方）进行sava-update或delete；设定为all则代表无论主控方执行任何操作
（Insert/update/delete...）都对其关联类时行同样的操作<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
;根据此属性的设置对相关联的对象采取相应的操作<br>
&nbsp;&nbsp;
cascade="all-delete-orphan"处理方式:<br>
&nbsp;&nbsp;
当保存当前对象时保存相关联的对象，相当于cascade="save-update"<br>
&nbsp;&nbsp;
当删除当前对象时删除相关联的对象，相当于cascade="delete"<br>
&nbsp;&nbsp;
当双方存在父子关系时，如果解除了子与父的关系则删除和父方解除关系的子方记录<br>
&nbsp;(当关联双方存在父子关系时，就可以把父方的cascade设为all-delete-orphan)<br>
&nbsp;5
在&lt;property&gt;标签中的access属性说明：<br>
&nbsp;&nbsp; 形式&lt;property name="name"
column="name" access="field/property"/&gt;<br>
&nbsp;
access默认为property，意思是：Hibernate不是直接访问持久化类中的name属性，而是访问setName()和getName()方法;<br>
&nbsp;
access="field",意思是:Hibernate不访问setName()和getName()方法，而是直接访问持久化类中的name属性<br>
6
hbm.xml文件的class标签中有一个polymorphism＝"explicit"属性，它的作用是：声明一个显式多态关系，声明为显式多态的类只有在代码中（如:list
object=createQuery("from
TuserProfile").list();这里显式指明了TuserProfile类）明确指定类名的时候才会返回此类实例;<br>
&nbsp;
如果要返回对应整个数据库中所有库表记录的数据对象，可用: List
obj=createQuery("from
object").list();但不会返回在映射文件中具有polymorphism＝"explicit"定义的类的实例</div>
<div>&nbsp; 方法<br>
1&nbsp; 加载数据的get和load方法区别:<br>
&nbsp;&nbsp; a
如果未能发现符合条件的记录，get方法返回null,load方法抛出一个ObjectNotFoundException异常<br>
&nbsp;&nbsp; b
load可以返回实体的代理类实例，get永远直接返回实体类<br>
&nbsp;&nbsp;&nbsp;
代理类实例:<br>
&nbsp;&nbsp;&nbsp;
实体类:<br>
&nbsp;&nbsp; c
load要在内部缓存和二级缓存中搜索现有数据，get则仅在内部缓存中进行数据查找(根据id查找)，如果在内部缓存中没有找到数据则直接从数据库中读取<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;
内部缓存（一级缓存）：其中保持了session当前所有关联实体的数据<br>
&nbsp;&nbsp;&nbsp;
二级缓存:存在于SessionFactory层次，由当前所有本SessionFactory构造的session实例共享<br>
2 session.find(hql,parameterValue,Hibernate Type of
parametervlaue)和session.iterator(hql,parameterValue,Hibernate type
of parameterValue) 方法的区别:<br>
&nbsp;session.find()返回的是List集合；session.find()
执行相应SQL后返回记录并构造相应的实体对象，再将其纳入缓存.find()不会对缓存进行数据查询，而是直接从数据库取记录，对于缓存只写不读<br>
&nbsp;session.iterator()返回的是Iterator集合；执行N+1次查询出所有符合条件的记录，首先查询满足条件的记录id，再根据id
查询所有记录；iterator首先在本地缓存中根据id查找对应的实体对象是否存在(类似session.load())，若存在则以此数据对象作为结
果返回；若未找到，则执行相应SQL语句从数据库获得对应的记录,并构建完整数据对象，再将其纳入缓存<br>
3 缓存对象的移除<br>
&nbsp;
session.evict(user)----从一级缓存中移除对象<br>
&nbsp;
sessionFactory.evict(Tuser.class,user.getId())-------从二级缓存中移除对象;二级缓存可以设定最大数据缓存量，达到峰值时自动对缓存中的较老数据进行移除；也可以手工移除（如前）<br>
4
session.save()先在一级缓存中查询要保存的对象，若找到则认为对象处于持久状态；不会把对象放在二级缓存，而是放在一级缓存<br>
&nbsp;
session.update()先在一级缓存中查询要保存的对象，若找到则认为对象处于持久状态；将在session.flush()时执行update的SQL语句(transaction.commit在真正提交数据库事务前会调用session.flush)<br>
&nbsp;
saveorupdate()无需用户判断对象的状态，其自动判断再执行save或者update<br>
5
saveorupdate()方法说明:该方法包含了save()与update()方法的功能，如果传入的参数是临时对象，就调用save()方法，如
果传入的参数是游离对象，就调用update()方法，如果传入的是持久化对象，那就直接返回.saveorupdate()方法如何判断一个对象是处于
临时状态还是游离对象根据的是以下条件，满足其一即可:<br>
&nbsp;1.java对象的ID取值为null<br>
&nbsp;2.java对象具有version属性并且取值为null<br>
&nbsp;3.在映射文件中为&lt;id&gt;元素设置了undaved-value属性，并且ID取值与undaved-value属性值匹配。<br>
&nbsp;4.在映射文件中为version属性设置了unsaved-value属性，并且version属性取值与unsaved-value属性值匹配.<br>
&nbsp;5.自定义了Hibernate的Interceptor实现类，并且Interceptor的isUnsaved()方法返回true.</div>
<div>实体对象的三种状态<br>
java中，对象不引用任何对象且不被任何对象引用时，就会被JVM回收，此时该对象才结束生命周期.<br>
session缓存:session缓存其实就是session的实现类sessionImp中定义的Map集合，以对象ID为键，以对象为值的形式保存.</div>
<div>1
Transient(自由状态):刚刚用new语句创建，还没有被持久化，不处于session的缓存中。即实体对象在内存中是自由存在的，它与数据库中的记录无关；处于临时状态的java对象被称为临时对象.<br>
&nbsp;&nbsp;&nbsp;
特征:1.不处在session的缓存中，也可以说，不被任何一个session实例关联.<br>
&nbsp; 2.在数据库中没有对应的记录.<br>
&nbsp;在以下情况下，java对象进入临时状态:<br>
&nbsp;
1.当通过new语句刚创建了一个java对象，它处于临时状态，此时不和数据库中的任何记录对应.<br>
&nbsp;
2.session的delete()方法能使一个持久化对象或游离对象转变为临时对象。对于游离对象，delete()方法从数据库中删除与它对应的记录;对于持久化对象，delete()方法从数据库中删除与它对应的记录，并且把它从session缓存中删除.<br>
&nbsp;<br>
2
Persistent(持久状态):已经被持久化，加入到了session缓存中。实体对象处于由Hibernate框架所管理的状态，这种状态下，实体
对象的引用被纳入Hibernate实体容器中加以管理;处于Persistent状态的对象，其变更将由Hibernate固化到数据库中<br>
何时变为持久状态:当实体对象处于自由状态时，通过Session.save方法可将其转换为Persistent状态，如果一个实体对象是由
Hibernate加载(如通过Session.load方法获得),那它也处于Persistent状态;处于持久化状态的实体即使没有调用
session.save()方法进行数据持久化，而只用了tx.commit()也会被保存到数据库<br>
持久化对象的特征:<br>
&nbsp;1.位于一个session实例的缓存中，也可以说，持久化对象总是被一个session实例关联.<br>
&nbsp;2.持久化对象和数据库中的相关记录对应<br>
&nbsp;3.session在清理缓存时，会根据持久化对象的属性变化，来同步更新数据库</div>
<div>&nbsp;3
Detached(游离状态):已经被持久化，但不处于session缓存当中.对应的Session实例关闭之后，此对象就处于游离状态<br>
&nbsp;例：<br>
&nbsp;Tuser user=new Tuser();<br>
&nbsp;user.setName("Emma");//此时实体对象user处于游离状态<br>
&nbsp;Tansaction tx=session.beginTransaction();<br>
&nbsp;session.save(user);//此时实体对象user已经由Hibernate纳入管理容器，处于Persistent状态<br>
&nbsp;tx.commit();<br>
&nbsp;session.close();//(Tag)&nbsp;&nbsp;&nbsp;&nbsp;
实体对象user此时状态为Detached，因为与其关联的session已经关闭&nbsp;&nbsp;&nbsp;</div>
<div>3 游离对象的特征:<br>
&nbsp;1.不再位于session缓存中，也可以说，游离对象不实被session关联.<br>
&nbsp;2.游离对象是由持久化对象转变来的，因此在数据库中可能还存在与它对应的记录(只要没删除该记录)</div>
<div>4
Transient状态和Detached状态的相同之处:两者都不被session关联.两者的区别:游离对象是由持久对象转变过来的，因此可能在数据
库中还存对应的记录，而临时对象在数据库中没有对应的记录.Detached对象可以再次与某个Session实例相关联而成为Persistent对
象;如下所示<br>
接Tag处:<br>
Transaction tx2=session2.beginTransaction();<br>
session2.update(user);//此时处于Detached状态的user对象再次借助session2由Hibernate纳入管理容器，恢复Persistent状态<br>
user.setName("Eric");<br>
tx2.commit();//由于user对象再次处于Persistent状态，因此其属性变更将自动由Hibernate固化到数据库<br>
5
Transient状态的对象与数据库中记录并不存在对应关系，它所包含的数据信息仅是上面的user.setName("Emma")这点而已；
Session.save()执行后，Hibernate对user对象进行了持久化，并为其赋予了主键值，这时user对象就与库表中具备相同id值的
记录相关联;所以，Transient状态的user对象与库表中的数据缺乏对应关系，而Detached状态的user对象，却在库表中存在相对应的记
录(由主键惟一确定)，简而言之，Transient状态中的实体对象，无主键信息，而Deatched状态的实体对象包含了其对应数据库记录的主键值;<br>
实体对象从Persistent状态转变为Transient状态一般由session.delete方法完成</div>
<div>6
Collection在判断两个对象是否相等的时候，会首先调用对象的hashCode方法，如果hashCode相同的话，　再调用equals方法，如果两次判断均为真，则认为对比的两个对象相等</div>
<div><br>
关联关系<br>
*********************一对多关系中，一方&lt;set&gt;的说明*********************************************<br>
1
当&lt;set&gt;中同时设置lazy和outer-join属性时，如果两者都为false则采用立即检索(因为outer-join="false"则不采用迫切左外连接，但lazy="false"则是指采用立即检索策略);<br>
如果lazy和outer-join其中一个为false另一个为true(不管谁是false谁是true),则以设置为true的那一个为准(即
lazy=true,outer-join=false则是采用延迟检索;相反采用迫切左外连接);如果两者均为true则同lazy=false,
outer-join=true(即采用迫切左外连接，outer-join优先级比lazy高);find()方法会忽略outer-join属性，即
outer-join对find方法无效;<br>
如果&lt;set&gt;中设有lazy且&lt;class&gt;中也设有lazy属性，则是以&lt;class&gt;中的为准;<br>
&nbsp;&nbsp;&nbsp;
对于get和find方法均是采用立即检索,与lazy的设置无关<br>
2
&lt;set&gt;中的batch-size属性可以理解为:在加载&lt;set&gt;中的&lt;one-to-many&gt;中的class类对象时，要初始化的对象数目，以便在后面再次需要初始化时不需要再访问数据库，从而提高数据访问速度<br>
3
&lt;set&gt;中一般要设置：lazy=true,outer-join="true",batch-size设为要在子方初始化的对象个数(一般为：3-10)</div>
<div>
************************多对一关系中，多方的说明******************************888<br>
1(设一方[customer.hbm.xml]的class中的lazy为A;多方[order.hbm.xml]的&lt;many-to-one&gt;中的outer-join为B)<br>
&nbsp;A=true,B=auto,则对于order.hbm.xml的&lt;many-to-one&gt;中的class指向的对象[customer]采用延迟检索，否则用迫切左外连接检索<br>
&nbsp;A=false,B=true,对于order关联的customer采用迫切左外连接检索<br>
&nbsp;A=true,B=false
对于order关联的customer对象采用延迟检索，否则采用立即检索<br>
&nbsp;
结论：当A=true时，则B无论设为什么均按照A的设置进行检索，只有当A=false时，才按B的设置进行检索(A的优先级大于B)<br>
2.hibernate.max_fetch_deepth:在迫切左外连接的多层数据表的检索中设置从第一层检索表开始的检索深度(即从第一层检索表开始要检索几层从第一层开始的检索表)</div>
<div>Java集合<br>
1.Set 集合中的对象不按特定方式排序，且没有重复对象;<br>
&nbsp;该接口主要有两个实现类HashSet和TreeSet。<br>
&nbsp;HashSet类按照哈希算法来存取集合中的对象，存取速度比较快。HashSet类还有一个子类LinkedHashSet类，它不仅实现了哈希算法，且实现了链表数据结构。TreeSet类实现了SortedSet接口&nbsp;&nbsp;，具有排序功能.<br>
&nbsp;为了保证HashSet能正常工作，要求当两个对象用equals()方法比较的结果为相等时，其哈希码也相等;即如果覆盖了equals()方法，也应该覆盖hashCode()方法</div>
<div>Set set = new HashSet();<br>
&nbsp;&nbsp;String s1 = new
String("hello");<br>
&nbsp;&nbsp;String s2 = s1;<br>
&nbsp;&nbsp;String s3 = new
String("world");<br>
&nbsp;&nbsp;set.add(s1);<br>
&nbsp;&nbsp;set.add(s2);<br>
&nbsp;&nbsp;set.add(s3);<br>
&nbsp;&nbsp;System.out.println("set的元素个数："
+ set.size());//==2</div>
<div>2 List
List的主要特征是其对象以线性方式存储，集合中允许存放重复对象。List接口主要的实现类有：LinkedList，ArrayList。
LinkedList采用链表数据结构，而ArrayList代表大小可变的数组.List接口还有一个实现类Vector，其功能和ArrayList
相似，两者的区别在于：Vector类的实现了同步机制，而ArrayList没有使用同步机制.<br>
&nbsp;List对集合中的对象按索引位置排序，允许按照对象在集合中的索引位置检索对象<br>
&nbsp;List的iterator()方法和Set的iterator()方法均返回Iterator对象，通过Iterator对象，可以遍历集合中的所有对象</div>
<div>3
Map:Map（映射）是一种把键对象和值对象进行映射的集合，其每一个元素都包含了一对键对象和值对象，而值对象仍可以是Map类型;向Map集合中加入元素时，必须提供一对键对象和值对象，从Map集合中检索元素时，只要给出键对象，就会返回对应的值对象。</div>
<div>Map map=new HashMap();<br>
map.put("1","Monday");<br>
map.put("2","Tuesday");&nbsp;<br>
map.put("3","Wendsday");<br>
map.put("4","Thursday");<br>
System.out.println("Map测试==="+map.get("2"));//=Tuesday<br>
Map集合中的键对象不允许重复，即任意两个键对象通过equals()方法比较的结果都是false,对于值对象则没有惟一性的要求，可以将任意多个键对象映射到同一个值对象上,但是后加入的值将会覆盖先加入的值.<br>
Map有两种比较常用的实现：HashMap和TreeMap。HashMap按照哈希算法来存取键对象有很好的存取性能</div>
<div>多对一关系中多方的配置<br>
&lt;many-to-one&nbsp; name="customer"&nbsp;
column="customer_id" class="pkg.customer"/&gt;<br>
&lt;set<br>
&nbsp;&nbsp;&nbsp;
name="order"<br>
&nbsp;&nbsp;&nbsp;
cascade="sava-update"<br>
&nbsp;&nbsp; inverse="true"&gt;<br>
&lt;key column="customer_id"/&gt;<br>
&lt;one-to-many class="pkg.order"/&gt;<br>
&lt;/set&gt;</div>
<br><img src ="http://www.blogjava.net/sutao/aggbug/134892.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-08-07 10:58 <a href="http://www.blogjava.net/sutao/articles/134892.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate二级缓存与一级缓存的关系</title><link>http://www.blogjava.net/sutao/articles/134888.html</link><dc:creator>苏醄</dc:creator><author>苏醄</author><pubDate>Tue, 07 Aug 2007 02:55:00 GMT</pubDate><guid>http://www.blogjava.net/sutao/articles/134888.html</guid><wfw:comment>http://www.blogjava.net/sutao/comments/134888.html</wfw:comment><comments>http://www.blogjava.net/sutao/articles/134888.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/sutao/comments/commentRss/134888.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/sutao/services/trackbacks/134888.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 主题: &nbsp;&nbsp;最近在看Hibernate的缓存，有一点没搞清楚                                                                         精华帖&nbsp;(0) :: 良好帖&nbsp;(0) :: 入门帖&nbsp;(13) :: 隐藏帖&nbsp;(0)&nbsp;            ...&nbsp;&nbsp;<a href='http://www.blogjava.net/sutao/articles/134888.html'>阅读全文</a><img src ="http://www.blogjava.net/sutao/aggbug/134888.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/sutao/" target="_blank">苏醄</a> 2007-08-07 10:55 <a href="http://www.blogjava.net/sutao/articles/134888.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>