﻿<?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>IT博客-forrest-文章分类-TomcaT</title><link>http://www.cnitblog.com/forrest/category/3705.html</link><description>对过去我已无法选择，但令我稍感安慰的是我还拥有现在，所以。。。。。
更弥足珍贵</description><language>zh-cn</language><lastBuildDate>Mon, 03 Oct 2011 15:13:15 GMT</lastBuildDate><pubDate>Mon, 03 Oct 2011 15:13:15 GMT</pubDate><ttl>60</ttl><item><title>tomcat 3.1在RedHat下的安装</title><link>http://www.cnitblog.com/forrest/articles/16253.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Fri, 01 Sep 2006 01:12:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/articles/16253.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/16253.html</wfw:comment><comments>http://www.cnitblog.com/forrest/articles/16253.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/16253.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/16253.html</trackback:ping><description><![CDATA[
		<table class="tbl" cellspacing="0" cellpadding="6" width="95%" align="center" border="0">
				<tbody>
						<tr>
								<td>
										<div align="center">
												<span class="ccwheading02">tomcat 3.1在RedHat下的安装</span>
										</div>
										<div align="center">
												<br /> </div>
								</td>
						</tr>
						<tr>
								<td>
										<hr size="1" />
										<div style="VISIBILITY: hidden; OVERFLOW: hidden; WIDTH: 1px; COLOR: white; HEIGHT: 1px">转自：动态网站制作指南 | www.knowsky.com</div>
										<table cellspacing="5" cellpadding="0" width="1%" align="right" border="0">
												<tbody>
														<tr>
																<td>
																		<script src="http://adimg.knowsky.com/ad/list.js">
																		</script>
																</td>
														</tr>
												</tbody>
										</table>
										<span class="t18">Jsp是sun在servlet基础上发展而来的一种新的web开发工具，在国外Ejb+jsp/servlet+应用服务器+数 据库已经已经成为电子商务站点的流行架构。tomcat3.1实现了最新的servlet2.2和jsp1.1标准，sun也 是推荐使用tomcat,本文介绍tomcat3.1在RedHat下的安装。 <br /><br />  在java.sun.com取得jdk1_2_2-<a href="http://www.knowsky.com/article.asp?typeid=60">Linux</a>-i386.tar.gz <br />  在http://jakarta.apache.org/builds/tomcat/release/v3.1/bin/取得jakarta-tomcat.tar.gz, <br />  在http://jakarta.apache.org/builds/tomcat/release/v3.1/bin/linux/i386/取得mod_jserv.so <br /><br />1、安装jdk1.2.2 #cp jdk1_2_2-linux-i386.tar.gz /usr/local #tar xvzf jdk1_2_2-linux-i386.tar.gz #ln -s jdk1.2.2 jdk #ln -s jdk/jre jre 设置$JAVA_HOME,$CLASSPATH #vi /etc/profile 加入： JAVA_HOME=/usr/local/jdk export JAVA_HOME CLASSPATH=/usr/local/jdk/lib:/usr/local/jre/lib export CLASSPATH PATH=$PAHT:/usr/local/jdk/bin:/usr/local/jre/bin <br /><br />2、安装tomcat #cp jakarta-tomcat.tar.gz /usr/local #tar xvzf jakarta-tomcat.tar.gz 退出重新登入 #cd /usr/local/jakarta-tomcat/bin 运行tomcat服务器 #./startup.sh start(用./shutdown.sh stop结束tomcat服务器） #lynx http://localhost:8080/ 看见了jsp/servlet的东西，并且能运行它的例子程序，那么你的tomcat服务器就安装成功了 <br /><br />3、和apache连接 tomcat本身其实就是一个web服务器，我们可以把他和apache等其他web服务器连接起来，这两个服务器 可以不在同一台机器上。底下的操作为在同一台机器上的情况，如果想把他们分开在两台计算机上，请 修改/usr/loca/jakarta-tomcat/conf/tomcat.conf #cp mod_jserv.so /your/apache/libexec #cp /usr/local/jakarta-tomcat/conf/tomcat.conf /your/apache/conf/path #vi /your/apache/conf/path/httpd.conf 加入 Include /your/apache/conf/path/httpd/tomcat.conf <br /><br />4、测试 重新启动你的apache, 然后运行tomcat服务器 #lynx http://localhost/examples/ 如果你看见了jsp、servlet目录，你的apche与tomcat已经连接成功了. <br /><br />5、一些说明： 如果你的jsp/servlet运行不了或者有错误，一般是你的CLASSPATH设置错误 如果你的apache是自己编译的，编译apache时请把--enable-module=so打开 <br /><br />关于tomcat的信息请到http://jakarta.apache.org <br />其他jsp方面的信息可以到http://java.sun.com/jsp </span>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cnitblog.com/forrest/aggbug/16253.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2006-09-01 09:12 <a href="http://www.cnitblog.com/forrest/articles/16253.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>前言</title><link>http://www.cnitblog.com/forrest/articles/16237.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Thu, 31 Aug 2006 10:45:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/articles/16237.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/16237.html</wfw:comment><comments>http://www.cnitblog.com/forrest/articles/16237.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/16237.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/16237.html</trackback:ping><description><![CDATA[
		<div class="navheader">
				<table width="100%" summary="Navigation header">
						<tbody>
								<tr>
										<th align="middle" colspan="3">前言</th>
								</tr>
								<tr>
										<td align="left" width="20%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<th align="middle" width="60%"> </th>
										<td align="right" width="20%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/quickstart.html"><font color="#002c99">下一页</font></a></td>
								</tr>
						</tbody>
				</table>
				<font color="#002c99">
						<hr />
				</font>
		</div>
		<div class="preface" lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h2 class="title">
												<a name="preface">
												</a>前言</h2>
								</div>
						</div>
						<div>
						</div>
				</div>
				<p>WARNING! This is a translated version of the English Hibernate reference documentation. The translated version might not be up to date! However, the differences should only be very minor. Consult the English reference documentation if you are missing information or encounter a translation error. If you like to contribute to a particular translation, contact us on the Hibernate developer mailing list. </p>
				<p>Translator(s): Xiaogang Cao &lt;caoxg@yahoo.com&gt; </p>
				<p>在今日的企业环境中，把面向对象的软件和关系数据库一起使用可能是相当麻烦、浪费时间的。Hibernate是一个面向Java环境的对象/关系数据库映射工具。对象/关系数据库映射(object/relational mapping (ORM))这个术语表示一种技术，用来把对象模型表示的对象映射到基于SQL的关系模型数据结构中去。 </p>
				<p>Hibernate不仅仅管理Java类到数据库表的映射（包括Java数据类型到SQL数据类型的映射），还提供数据查询和获取数据的方法，可以大幅度减少开发时人工使用SQL和JDBC处理数据的时间。 </p>
				<p>Hibernate的目标是对于开发者通常的数据持久化相关的编程任务，解放其中的95%。对于以数据为中心的程序来说,它们往往只在数据库中使用存储过程来实现商业逻辑,Hibernate可能不是最好的解决方案;对于那些在基于Java的中间层应用中，它们实现面向对象的业务模型和商业逻辑的应用，Hibernate是最有用的。不管怎样，Hibernate一定可以帮助你消除或者包装那些针对特定厂商的SQL代码，并且帮你把结果集从表格式的表示形式转换到一系列的对象去。 </p>
				<p>如果你对Hibernate和对象/关系数据库映射还是个新手，或者甚至对Java也不熟悉，请按照下面的步骤来学习。 </p>
				<div class="orderedlist">
						<ol type="1">
								<li>
										<p>阅读这个30分钟就可以结束的<a title="第&amp;nbsp;1&amp;nbsp;章&amp;nbsp;在Tomcat中快速上手" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/quickstart.html"><font color="#002c99">第 1 章 <i>在Tomcat中快速上手</i></font></a>，它使用Tomcat。 </p>
								</li>
								<li>
										<p>阅读<a title="第&amp;nbsp;2&amp;nbsp;章&amp;nbsp;体系结构" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/architecture.html"><font color="#002c99">第 2 章 <i>体系结构</i></font></a>来理解Hibernate可以使用的环境。 </p>
								</li>
								<li>
										<p>查看Hibernate发行包中的<tt class="literal">eg/</tt>目录，里面有一个简单的独立运行的程序。把你的JDBC驱动拷贝到<tt class="literal">lib/</tt>目录下，修改一下<tt class="literal">src/hibernate.properties</tt>,指定其中你的数据库的信息。进入命令行，切换到你的发行包的目录，输入<tt class="literal">ant eg</tt>(使用了Ant），或者在Windows操作系统中使用<tt class="literal">build eg</tt>。 </p>
								</li>
								<li>
										<p>把这份参考文档作为你学习的主要信息来源。 </p>
								</li>
								<li>
										<p>在Hibernate 的网站上可以找到经常提问的问题与解答(FAQ)。 </p>
								</li>
								<li>
										<p>在Hibernate网站上还有第三方的演示、示例和教程的链接。 </p>
								</li>
								<li>
										<p>Hibernate网站的“社区(Community Area)”是讨论关于设计模式以及很多整合方案(Tomcat, JBoss, Spring,Struts, EJB,等等)的好地方。 </p>
								</li>
						</ol>
				</div>
				<p>如果你有问题，请使用Hibernate网站上链接的用户论坛。我们也提供一个JIRA问题追踪系统，来搜集bug报告和新功能请求。如果你对开发Hibernate有兴趣，请加入开发者的邮件列表。 （译者注:http://www.redsaga.com 和一个非官方的由爱好者设立的中文论坛：http://forum.hibernate.org.cn 都随时欢迎您的访问。） </p>
				<p>商业开发、产品支持和Hibernate培训可以通过JBoss Inc.获得。（请查阅：http://www.hibernate.org/SupportTraining/）。Hibernate是一个包含于JBoss Professional Open Source产品套件的项目。 </p>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="preface-translate-comments-zh-cn">
														</a>1. 翻译说明</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>本文档的翻译是在网络上协作进行的，也会不断根据Hibernate的升级进行更新。提供此文档的目的是为了减缓学习Hibernate的坡度，而非代替原文档。我们建议所有有能力的读者都直接阅读英文原文。若您对翻译有异议，或发现翻译错误，敬请不吝赐教，报告到如下email地址：caoxg at redsaga.com </p>
						<p>翻译是从版本2.0.4开始的。第2.0.4版本中，的"集合类"、"组件"是由jlinux翻译，"父子关系"是由muziq翻译，"事务和并行"、"映射实例"是由liangchen翻译，其他各章节是由曹晓钢翻译的，第18、19、20章，bruce、robbin也有贡献。曹晓钢也进行了全书从2.0.4更新到2.1.1、2.1.2、2.1.3版本的工作。 2.1.3版本后,Hibernate开始使用标准化的统一翻译流程,第一次初始化由曹晓钢完成提交。 </p>
						<p>更详细的翻译者与翻译更新情况，请查阅CVS目录下的TRANSLATE-LOG.TXT文件。 </p>
						<p>版权声明 </p>
						<p>Hibernate英文文档属于Hibernate发行包的一部分，遵循LGPL协议。本翻译版本同样遵循LGPL协议。参与翻译的译者一致同意放弃除署名权外对本翻译版本的其它权利要求。 </p>
						<p>您可以自由链接、下载、传播此文档，或者放置在您的网站上，甚至作为产品的一部分发行。但前提是必须保证全文完整转载，包括完整的版权信息和作译者声明。这里“完整”的含义是，不能进行任何删除/增添/注解。若有删除/增添/注解，必须逐段明确声明那些部分并非本文档的一部分。 </p>
				</div>
		</div>
		<div class="navfooter">
				<hr />
				<table width="100%" summary="Navigation footer">
						<tbody>
								<tr>
										<td align="left" width="40%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<td align="middle" width="20%">
												<a accesskey="u" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">上一级</font>
												</a>
										</td>
										<td align="right" width="40%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/quickstart.html"><font color="#002c99">下一页</font></a></td>
								</tr>
								<tr>
										<td valign="top" align="left" width="40%">HIBERNATE - 符合Java习惯的关系数据库持久化 </td>
										<td align="middle" width="20%">
												<a accesskey="h" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">起始页</font>
												</a>
										</td>
										<td valign="top" align="right" width="40%"> 第 1 章 在Tomcat中快速上手</td>
								</tr>
						</tbody>
				</table>
		</div>
<img src ="http://www.cnitblog.com/forrest/aggbug/16237.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2006-08-31 18:45 <a href="http://www.cnitblog.com/forrest/articles/16237.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第 16 章 示例：父子关系(Parent Child Relationships)</title><link>http://www.cnitblog.com/forrest/articles/16235.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Thu, 31 Aug 2006 10:43:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/articles/16235.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/16235.html</wfw:comment><comments>http://www.cnitblog.com/forrest/articles/16235.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/16235.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/16235.html</trackback:ping><description><![CDATA[
		<div class="navheader">
				<table width="100%" summary="Navigation header">
						<tbody>
								<tr>
										<th align="middle" colspan="3">第 16 章 示例：父子关系(Parent Child Relationships)</th>
								</tr>
								<tr>
										<td align="left" width="20%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/toolsetguide.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<th align="middle" width="60%"> </th>
										<td align="right" width="20%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/example-weblog.html"><font color="#002c99">下一页</font></a></td>
								</tr>
						</tbody>
				</table>
				<font color="#002c99">
						<hr />
				</font>
		</div>
		<div class="chapter" lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h2 class="title">
												<a name="example-parentchild">
												</a>第 16 章 示例：父子关系(Parent Child Relationships)</h2>
								</div>
						</div>
						<div>
						</div>
				</div>
				<p>刚刚接触Hibernate的人大多是从父子关系（parent / child type relationship）的建模入手的。父子关系的建模有两种方法。比较简便、直观的方法就是在实体类<tt class="literal">Parent</tt>和<tt class="literal">Child</tt>之间建立<tt class="literal">&lt;one-to-many&gt;</tt>的关联关系，从<tt class="literal">Parent</tt>指向<tt class="literal">Child</tt>，对新手来说尤其如此。但还有另一种方法，就是将<tt class="literal">Child</tt>声明为一个<tt class="literal">&lt;composite-element&gt;</tt>（组合元素）。 可以看出在Hibernate中使用一对多关联比composite element更接近于通常parent / child关系的语义。下面我们会阐述如何使用<span class="emphasis"><em>双向可级联的一对多关联(bidirectional one to many association with cascades)</em></span>去建立有效、优美的parent / child关系。这一点也不难！ </p>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="example-parentchild-collections">
														</a>16.1. 关于collections</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>在Hibernate下，实体类将collection作为自己的一个逻辑单元，而不是被容纳的多个实体。这非常重要！它主要体现为以下几点： </p>
						<div class="itemizedlist">
								<ul type="disc">
										<li>
												<p>当删除或增加collection中对象的时候，拥有这个collection的实体对象的版本值会递增。 </p>
										</li>
										<li>
												<p>如果一个从collection中移除的对象是一个值类型(value type)的实例，比如composite element，那么这个对象的持久化状态将会终止，其在数据库中对应的记录会被删除。同样的，向collection增加一个value type的实例将会使之立即被持久化。 </p>
										</li>
										<li>
												<p>另一方面，如果从一对多或多对多关联的collection中移除一个实体，在缺省情况下这个对象并不会被删除。这个行为是完全合乎逻辑的－－改变一个实体的内部状态不应该使与它关联的实体消失掉！同样的，向collection增加一个实体不会使之被持久化。 </p>
										</li>
								</ul>
						</div>
						<p>实际上，向Collection增加一个实体的缺省动作只是在两个实体之间创建一个连接而已，同样移除的时候也只是删除连接。这种处理对于所有的情况都是合适的。不适合所有情况的其实是父子关系本身，因为子对象是否存在依赖于父对象的生存周期。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="example-parentchild-bidir">
														</a>16.2. 双向的一对多关系(Bidirectional one-to-many)</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>让我们从一个简单的例子开始，假设要实现一个从类<tt class="literal">Parent</tt>到类<tt class="literal">Child</tt>的一对多关系。 </p>
						<pre class="programlisting">&lt;set name="children"&gt;
    &lt;key column="parent_id"/&gt;
    &lt;one-to-many class="Child"/&gt;
&lt;/set&gt;</pre>
						<p>如果我们运行下面的代码 </p>
						<pre class="programlisting">Parent p = .....;
Child c = new Child();
p.getChildren().add(c);
session.save(c);
session.flush();</pre>
						<p>Hibernate就会产生下面的两条SQL语句: </p>
						<div class="itemizedlist">
								<ul type="disc">
										<li>
												<p>一条<tt class="literal">INSERT</tt>语句，用于创建对象<tt class="literal">c</tt>对应的数据库记录</p>
										</li>
										<li>
												<p>一条<tt class="literal">UPDATE</tt>语句，用于创建从对象<tt class="literal">p</tt>到对象<tt class="literal">c</tt>的连接 </p>
										</li>
								</ul>
						</div>
						<p>这样做不仅效率低，而且违反了列<tt class="literal">parent_id</tt>非空的限制。 </p>
						<p>底层的原因是，对象<tt class="literal">p</tt>到对象<tt class="literal">c</tt>的连接（外键<tt class="literal">parent_id</tt>）没有被当作是<tt class="literal">Child</tt>对象状态的一部分，也没有在<tt class="literal">INSERT</tt>的时候被创建。解决的办法是，在<tt class="literal">Child</tt>一端设置映射。 </p>
						<pre class="programlisting">&lt;many-to-one name="parent" column="parent_id" not-null="true"/&gt;</pre>
						<p>（我们还需要为类<tt class="literal">Child</tt>添加<tt class="literal">parent</tt>属性） </p>
						<p>现在实体<tt class="literal">Child</tt>在管理连接的状态，为了使collection不更新连接，我们使用<tt class="literal">inverse</tt>属性。 </p>
						<pre class="programlisting">&lt;set name="children" inverse="true"&gt;
    &lt;key column="parent_id"/&gt;
    &lt;one-to-many class="Child"/&gt;
&lt;/set&gt;</pre>
						<p>下面的代码是用来添加一个新的<tt class="literal">Child</tt></p>
						<pre class="programlisting">Parent p = (Parent) session.load(Parent.class, pid);
Child c = new Child();
c.setParent(p);
p.getChildren().add(c);
session.save(c);
session.flush();</pre>
						<p>现在，只会有一条<tt class="literal">INSERT</tt>语句被执行！ </p>
						<p>为了让事情变得井井有条，可以为<tt class="literal">Parent</tt>加一个<tt class="literal">addChild()</tt>方法。 </p>
						<pre class="programlisting">public void addChild(Child c) {
    c.setParent(this);
    children.add(c);
}</pre>
						<p>现在，添加<tt class="literal">Child</tt>的代码就是这样 </p>
						<pre class="programlisting">Parent p = (Parent) session.load(Parent.class, pid);
Child c = new Child();
p.addChild(c);
session.save(c);
session.flush();</pre>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="example-parentchild-cascades">
														</a>16.3. 级联生命周期（Cascading lifecycle）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>对每个对象调用<tt class="literal">save()</tt>方法很麻烦，我们可以用级联来解决这个问题。 </p>
						<pre class="programlisting">&lt;set name="children" inverse="true" cascade="all"&gt;
    &lt;key column="parent_id"/&gt;
    &lt;one-to-many class="Child"/&gt;
&lt;/set&gt;</pre>
						<p>配置级联以后，代码就可以这样写： </p>
						<pre class="programlisting">Parent p = (Parent) session.load(Parent.class, pid);
Child c = new Child();
p.addChild(c);
session.flush();</pre>
						<p>同样的，保存或删除<tt class="literal">Parent</tt>对象的时候并不需要遍历其子对象。 下面的代码会删除对象<tt class="literal">p</tt>及其所有子对象对应的数据库记录。 </p>
						<pre class="programlisting">Parent p = (Parent) session.load(Parent.class, pid);
session.delete(p);
session.flush();</pre>
						<p>然而，这段代码 </p>
						<pre class="programlisting">Parent p = (Parent) session.load(Parent.class, pid);
Child c = (Child) p.getChildren().iterator().next();
p.getChildren().remove(c);
c.setParent(null);
session.flush();</pre>
						<p>不会从数据库删除<tt class="literal">c</tt>；它只会删除与<tt class="literal">p</tt>之间的连接（并且会导致违反<tt class="literal">NOT NULL</tt>约束，在这个例子中）。你需要明确调用<tt class="literal">Child</tt>的<tt class="literal">delete()</tt>方法。 </p>
						<pre class="programlisting">Parent p = (Parent) session.load(Parent.class, pid);
Child c = (Child) p.getChildren().iterator().next();
p.getChildren().remove(c);
session.delete(c);
session.flush();</pre>
						<p>在我们的例子中，如果我们规定没有父对象的话，子对象就不应该存在，如果将子对象从collection中移除，实际上我们是想删除它。要实现这种要求，就必须使用<tt class="literal">cascade="all-delete-orphan"</tt>。 </p>
						<pre class="programlisting">&lt;set name="children" inverse="true" cascade="all-delete-orphan"&gt;
    &lt;key column="parent_id"/&gt;
    &lt;one-to-many class="Child"/&gt;
&lt;/set&gt;</pre>
						<p>注意：即使在collection一方的映射中指定<tt class="literal">inverse="true"</tt>，在遍历collection的时候级联操作仍然会执行。如果你想要通过级联进行子对象的插入、删除、更新操作，就必须把它加到collection中，只调用<tt class="literal">setParent()</tt>是不够的。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="example-parentchild-update">
														</a>16.4. 级联更新（Using cascading <tt class="literal">update()</tt>）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>假设我们从<tt class="literal">Session</tt>中装入了一个<tt class="literal">Parent</tt>对象，用户界面对其进行了修改，然后我们希望在一个新的Session里面调用<tt class="literal">update()</tt>来更新它。对象<tt class="literal">Parent</tt>包含了子对象的集合，由于打开了级联更新，Hibernate需要知道哪些子对象是新的，哪些是数据库中已经存在的。我们假设<tt class="literal">Parent</tt>和<tt class="literal">Child</tt>对象的标识属性的类型为<tt class="literal">java.lang.Long</tt>。Hibernate会使用标识属性的值来判断哪些子对象是新的。(你也可以使用version 或 timestamp 属性，参见<a title="9.4.2.&amp;nbsp;更新从session脱离的对象" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/manipulatingdata.html#manipulatingdata-updating-detached"><font color="#002c99">第 9.4.2 节 “更新从session脱离的对象”</font></a>.) </p>
						<p>
								<tt class="literal">unsaved-value</tt>属性是用来表示新实例的标识属性值的，缺省为"null"，用在<tt class="literal">Long</tt>类型的标识类型再好不过了。如果我们使用原始类型作为标识类型的话，我们在配置<tt class="literal">Child</tt>类映射的时候就必须写： </p>
						<pre class="programlisting">&lt;id name="id" type="long" unsaved-value="0"&gt;</pre>
						<p>(为版本和时间戳属性进行映射，也会有另一个叫做<tt class="literal">unsaved-value</tt>的属性。) </p>
						<p>下面的代码会更新<tt class="literal">parent</tt>和<tt class="literal">child</tt>对象，并且插入<tt class="literal">newChild</tt>对象。 </p>
						<pre class="programlisting">//parent and child were both loaded in a previous session
parent.addChild(child);
Child newChild = new Child();
parent.addChild(newChild);
session.update(parent);
session.flush();</pre>
						<p>好的，对于自动生成标识的情况这样做很方便，但是自分配的标识和复合标识怎么办呢？这是有点麻烦，因为unsaved-value无法区分新对象（标识是用户指定的）和前一个Session装入的对象。在这种情况下，你可能需要给Hibernate一些提示，在调用<tt class="literal">update(parent)</tt>之前： </p>
						<div class="itemizedlist">
								<ul type="disc">
										<li>
												<p>在这个类的<tt class="literal">&lt;version&gt;</tt> or <tt class="literal">&lt;timestamp&gt;</tt>属性映射上定义<tt class="literal">unsaved-value="null"</tt>或者<tt class="literal">unsaved-value="negative"</tt>。 </p>
										</li>
										<li>
												<p>在对父对象执行<tt class="literal">update(parent)</tt>之前，设定<tt class="literal">unsaved-value="none"</tt>并且显式的调用<tt class="literal">save()</tt>在数据库创建新子对象 </p>
										</li>
										<li>
												<p>在对父对象执行<tt class="literal">update(parent)</tt>之前，设定<tt class="literal">unsaved-value="any"</tt>并且显式的调用<tt class="literal">update()</tt>更新已经装入的子对象 </p>
										</li>
								</ul>
						</div>
						<p>
								<tt class="literal">none</tt>是自分配标识和复合标识的<tt class="literal">unsaved-value</tt>的缺省值。 </p>
						<p>还有一种可能情况，有一个名为<tt class="literal">isUnsaved()</tt>的<tt class="literal">拦截器（Interceptor）</tt>方法，它允许应用程序自己实现新实例的判断。比如，你可以自己定义一个持久类的祖先类： </p>
						<pre class="programlisting">public class Persistent {
    private boolean _saved = false;
    public void onSave() {
        _saved=true;
    }
    public void onLoad() {
        _saved=true;
    }
    ......
    public boolean isSaved() {
        return _saved;
    }
}</pre>
						<p>（<tt class="literal">saved</tt>属性是不会被持久化的。) 现在在<tt class="literal">onLoad()</tt>和<tt class="literal">onSave()</tt>外，还要实现<tt class="literal">isUnsaved()</tt>。 </p>
						<pre class="programlisting">public Boolean isUnsaved(Object entity) {
    if (entity instanceof Persistent) {
        return new Boolean( !( (Persistent) entity ).isSaved() );
    }
    else {
        return null;
    }
}

public boolean onLoad(Object entity, 
    Serializable id,
    Object[] state,
    String[] propertyNames,
    Type[] types) {

    if (entity instanceof Persistent) ( (Persistent) entity ).onLoad();
    return false;
}

public boolean onSave(Object entity,
    Serializable id,
    Object[] state,
    String[] propertyNames,
    Type[] types) {
        
    if (entity instanceof Persistent) ( (Persistent) entity ).onSave();
    return false;
}</pre>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="example-parentchild-conclusion">
														</a>16.5. 结论</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>这个问题往往让新手感到迷惑，它确实不太容易消化。不过，经过一些实践以后，你会感觉越来越顺手。父子对象模式已经被广泛的应用在Hibernate应用程序中。 </p>
						<p>在第一段中我们曾经提到另一个方案。复合元素的语义与父子关系是等同的，但是我们并没有详细讨论。很不幸复合元素还有两个重大限制:复合元素不能拥有collections，并且，除了用于惟一的父对象外，它们不能再作为其它任何实体的子对象。（但是，通过使用<tt class="literal">&lt;idbag&gt;</tt>映射，它们<span class="emphasis"><em>可能</em></span>拥有代理主键。） </p>
				</div>
		</div>
		<div class="navfooter">
				<hr />
				<table width="100%" summary="Navigation footer">
						<tbody>
								<tr>
										<td align="left" width="40%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/toolsetguide.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<td align="middle" width="20%">
												<a accesskey="u" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">上一级</font>
												</a>
										</td>
										<td align="right" width="40%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/example-weblog.html"><font color="#002c99">下一页</font></a></td>
								</tr>
								<tr>
										<td valign="top" align="left" width="40%">第 15 章 工具箱指南 </td>
										<td align="middle" width="20%">
												<a accesskey="h" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">起始页</font>
												</a>
										</td>
										<td valign="top" align="right" width="40%"> 第 17 章 示例：Weblog 应用程序</td>
								</tr>
						</tbody>
				</table>
		</div>
<img src ="http://www.cnitblog.com/forrest/aggbug/16235.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2006-08-31 18:43 <a href="http://www.cnitblog.com/forrest/articles/16235.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第 17 章 示例：Weblog 应用程序</title><link>http://www.cnitblog.com/forrest/articles/16236.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Thu, 31 Aug 2006 10:43:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/articles/16236.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/16236.html</wfw:comment><comments>http://www.cnitblog.com/forrest/articles/16236.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/16236.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/16236.html</trackback:ping><description><![CDATA[
		<div class="navheader">
				<table width="100%" summary="Navigation header">
						<tbody>
								<tr>
										<th align="middle" colspan="3">第 17 章 示例：Weblog 应用程序</th>
								</tr>
								<tr>
										<td align="left" width="20%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/example-parentchild.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<th align="middle" width="60%"> </th>
										<td align="right" width="20%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/example-mappings.html"><font color="#002c99">下一页</font></a></td>
								</tr>
						</tbody>
				</table>
				<font color="#002c99">
						<hr />
				</font>
		</div>
		<div class="chapter" lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h2 class="title">
												<a name="example-weblog">
												</a>第 17 章 示例：Weblog 应用程序</h2>
								</div>
						</div>
						<div>
						</div>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="example-weblog-classes">
														</a>17.1. 持久化类</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>下面的两个持久化类表示一个weblog,和在其中张贴的一个贴子。他们是标准的父/子关系模型，但是我们会用一个排序包（ordered bag)而非集合(set)。 </p>
						<pre class="programlisting">package eg;

import java.util.List;

public class Blog {
    private Long _id;
    private String _name;
    private List _items;

    public Long getId() {
        return _id;
    }
    public List getItems() {
        return _items;
    }
    public String getName() {
        return _name;
    }
    public void setId(Long long1) {
        _id = long1;
    }
    public void setItems(List list) {
        _items = list;
    }
    public void setName(String string) {
        _name = string;
    }
}</pre>
						<pre class="programlisting">package eg;

import java.text.DateFormat;
import java.util.Calendar;

public class BlogItem {
    private Long _id;
    private Calendar _datetime;
    private String _text;
    private String _title;
    private Blog _blog;

    public Blog getBlog() {
        return _blog;
    }
    public Calendar getDatetime() {
        return _datetime;
    }
    public Long getId() {
        return _id;
    }
    public String getText() {
        return _text;
    }
    public String getTitle() {
        return _title;
    }
    public void setBlog(Blog blog) {
        _blog = blog;
    }
    public void setDatetime(Calendar calendar) {
        _datetime = calendar;
    }
    public void setId(Long long1) {
        _id = long1;
    }
    public void setText(String string) {
        _text = string;
    }
    public void setTitle(String string) {
        _title = string;
    }
}</pre>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="example-weblog-mappings">
														</a>17.2. Hibernate 映射</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>下列的XML映射应该是很直白的。 </p>
						<pre class="programlisting">&lt;?xml version="1.0"?&gt;
&lt;!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"&gt;

&lt;hibernate-mapping package="eg"&gt;
    &lt;class 
        name="Blog" 
        table="BLOGS" 
        lazy="true"&gt;
        
        &lt;id 
            name="id" 
            column="BLOG_ID"&gt;
            
            &lt;generator class="native"/&gt;
            
        &lt;/id&gt;
        
        &lt;property 
            name="name" 
            column="NAME" 
            not-null="true" 
            unique="true"/&gt;
            
        &lt;bag 
            name="items" 
            inverse="true" 
            lazy="true"
            order-by="DATE_TIME" 
            cascade="all"&gt;
            
            &lt;key column="BLOG_ID"/&gt;
            &lt;one-to-many class="BlogItem"/&gt;
            
        &lt;/bag&gt;
        
    &lt;/class&gt;
    
&lt;/hibernate-mapping&gt;</pre>
						<pre class="programlisting">&lt;?xml version="1.0"?&gt;
&lt;!DOCTYPE hibernate-mapping PUBLIC 
        "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
        "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"&gt;

&lt;hibernate-mapping package="eg"&gt;
    
    &lt;class 
        name="BlogItem" 
        table="BLOG_ITEMS" 
        dynamic-update="true"&gt;
        
        &lt;id 
            name="id" 
            column="BLOG_ITEM_ID"&gt;
            
            &lt;generator class="native"/&gt;
            
        &lt;/id&gt;
        
        &lt;property 
            name="title" 
            column="TITLE" 
            not-null="true"/&gt;
            
        &lt;property 
            name="text" 
            column="TEXT" 
            not-null="true"/&gt;
            
        &lt;property 
            name="datetime" 
            column="DATE_TIME" 
            not-null="true"/&gt;
            
        &lt;many-to-one 
            name="blog" 
            column="BLOG_ID" 
            not-null="true"/&gt;
            
    &lt;/class&gt;
    
&lt;/hibernate-mapping&gt;</pre>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="example-weblog-code">
														</a>17.3. Hibernate 代码</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>下面的类演示了我们可以使用Hibernate对这些类所进行的操作。 </p>
						<pre class="programlisting">package eg;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.Query;
import net.sf.hibernate.Session;
import net.sf.hibernate.SessionFactory;
import net.sf.hibernate.Transaction;
import net.sf.hibernate.cfg.Configuration;
import net.sf.hibernate.tool.hbm2ddl.SchemaExport;

public class BlogMain {
    
    private SessionFactory _sessions;
    
    public void configure() throws HibernateException {
        _sessions = new Configuration()
            .addClass(Blog.class)
            .addClass(BlogItem.class)
            .buildSessionFactory();
    }
    
    public void exportTables() throws HibernateException {
        Configuration cfg = new Configuration()
            .addClass(Blog.class)
            .addClass(BlogItem.class);
        new SchemaExport(cfg).create(true, true);
    }
    
    public Blog createBlog(String name) throws HibernateException {
        
        Blog blog = new Blog();
        blog.setName(name);
        blog.setItems( new ArrayList() );
        
        Session session = _sessions.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            session.save(blog);
            tx.commit();
        }
        catch (HibernateException he) {
            if (tx!=null) tx.rollback();
            throw he;
        }
        finally {
            session.close();
        }
        return blog;
    }
    
    public BlogItem createBlogItem(Blog blog, String title, String text)
                        throws HibernateException {
        
        BlogItem item = new BlogItem();
        item.setTitle(title);
        item.setText(text);
        item.setBlog(blog);
        item.setDatetime( Calendar.getInstance() );
        blog.getItems().add(item);
        
        Session session = _sessions.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            session.update(blog);
            tx.commit();
        }
        catch (HibernateException he) {
            if (tx!=null) tx.rollback();
            throw he;
        }
        finally {
            session.close();
        }
        return item;
    }
    
    public BlogItem createBlogItem(Long blogid, String title, String text)
                        throws HibernateException {
        
        BlogItem item = new BlogItem();
        item.setTitle(title);
        item.setText(text);
        item.setDatetime( Calendar.getInstance() );
        
        Session session = _sessions.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            Blog blog = (Blog) session.load(Blog.class, blogid);
            item.setBlog(blog);
            blog.getItems().add(item);
            tx.commit();
        }
        catch (HibernateException he) {
            if (tx!=null) tx.rollback();
            throw he;
        }
        finally {
            session.close();
        }
        return item;
    }
    
    public void updateBlogItem(BlogItem item, String text)
                    throws HibernateException {
        
        item.setText(text);
        
        Session session = _sessions.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            session.update(item);
            tx.commit();
        }
        catch (HibernateException he) {
            if (tx!=null) tx.rollback();
            throw he;
        }
        finally {
            session.close();
        }
    }
    
    public void updateBlogItem(Long itemid, String text)
                    throws HibernateException {
    
        Session session = _sessions.openSession();
        Transaction tx = null;
        try {
            tx = session.beginTransaction();
            BlogItem item = (BlogItem) session.load(BlogItem.class, itemid);
            item.setText(text);
            tx.commit();
        }
        catch (HibernateException he) {
            if (tx!=null) tx.rollback();
            throw he;
        }
        finally {
            session.close();
        }
    }
    
    public List listAllBlogNamesAndItemCounts(int max)
                    throws HibernateException {
        
        Session session = _sessions.openSession();
        Transaction tx = null;
        List result = null;
        try {
            tx = session.beginTransaction();
            Query q = session.createQuery(
                "select blog.id, blog.name, count(blogItem) " +
                "from Blog as blog " +
                "left outer join blog.items as blogItem " +
                "group by blog.name, blog.id " +
                "order by max(blogItem.datetime)"
            );
            q.setMaxResults(max);
            result = q.list();
            tx.commit();
        }
        catch (HibernateException he) {
            if (tx!=null) tx.rollback();
            throw he;
        }
        finally {
            session.close();
        }
        return result;
    }
    
    public Blog getBlogAndAllItems(Long blogid)
                    throws HibernateException {
        
        Session session = _sessions.openSession();
        Transaction tx = null;
        Blog blog = null;
        try {
            tx = session.beginTransaction();
            Query q = session.createQuery(
                "from Blog as blog " +
                "left outer join fetch blog.items " +
                "where blog.id = :blogid"
            );
            q.setParameter("blogid", blogid);
            blog  = (Blog) q.list().get(0);
            tx.commit();
        }
        catch (HibernateException he) {
            if (tx!=null) tx.rollback();
            throw he;
        }
        finally {
            session.close();
        }
        return blog;
    }
    
    public List listBlogsAndRecentItems() throws HibernateException {
        
        Session session = _sessions.openSession();
        Transaction tx = null;
        List result = null;
        try {
            tx = session.beginTransaction();
            Query q = session.createQuery(
                "from Blog as blog " +
                "inner join blog.items as blogItem " +
                "where blogItem.datetime &gt; :minDate"
            );

            Calendar cal = Calendar.getInstance();
            cal.roll(Calendar.MONTH, false);
            q.setCalendar("minDate", cal);
            
            result = q.list();
            tx.commit();
        }
        catch (HibernateException he) {
            if (tx!=null) tx.rollback();
            throw he;
        }
        finally {
            session.close();
        }
        return result;
    }
}</pre>
				</div>
		</div>
		<div class="navfooter">
				<hr />
				<table width="100%" summary="Navigation footer">
						<tbody>
								<tr>
										<td align="left" width="40%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/example-parentchild.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<td align="middle" width="20%">
												<a accesskey="u" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">上一级</font>
												</a>
										</td>
										<td align="right" width="40%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/example-mappings.html"><font color="#002c99">下一页</font></a></td>
								</tr>
								<tr>
										<td valign="top" align="left" width="40%">第 16 章 示例：父子关系(Parent Child Relationships) </td>
										<td align="middle" width="20%">
												<a accesskey="h" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">起始页</font>
												</a>
										</td>
										<td valign="top" align="right" width="40%"> 第 18 章 示例：不同的映射</td>
								</tr>
						</tbody>
				</table>
		</div>
<img src ="http://www.cnitblog.com/forrest/aggbug/16236.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2006-08-31 18:43 <a href="http://www.cnitblog.com/forrest/articles/16236.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第 15 章 工具箱指南</title><link>http://www.cnitblog.com/forrest/articles/16234.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Thu, 31 Aug 2006 10:42:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/articles/16234.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/16234.html</wfw:comment><comments>http://www.cnitblog.com/forrest/articles/16234.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/16234.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/16234.html</trackback:ping><description><![CDATA[
		<div class="navheader">
				<table width="100%" summary="Navigation header">
						<tbody>
								<tr>
										<th align="middle" colspan="3">第 15 章 工具箱指南</th>
								</tr>
								<tr>
										<td align="left" width="20%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/performance.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<th align="middle" width="60%"> </th>
										<td align="right" width="20%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/example-parentchild.html"><font color="#002c99">下一页</font></a></td>
								</tr>
						</tbody>
				</table>
				<font color="#002c99">
						<hr />
				</font>
		</div>
		<div class="chapter" lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h2 class="title">
												<a name="toolsetguide">
												</a>第 15 章 工具箱指南</h2>
								</div>
						</div>
						<div>
						</div>
				</div>
				<p>通过Hibernate项目中提供的几个命令行工具(他们也被当作项目的一部分不断得到维护),还有XDoclet,Middlegen和AndroMDA内置的对Hibernate的支持,可以在几个不同的环境(SQL,java代码,xml映射文件)中进行相互转换(roundtrip)。 </p>
				<p>Hibernate的主发行包中附带了最重要的工具（甚至在Hibernate内部也可以快速调用这个工具）： </p>
				<div class="itemizedlist">
						<ul type="disc">
								<li>
										<p>从映射文件到DDL schema的生成器（也就是<tt class="literal">SchemaExport</tt>和<tt class="literal">hbm2ddl</tt>） </p>
								</li>
						</ul>
				</div>
				<p>Hibernate项目直接提供的其他工具在一个单独的发行包中发布，<span class="emphasis"><em>Hibernate Extensions</em></span>。这个发行包包含了下列任务的工具： </p>
				<div class="itemizedlist">
						<ul type="disc">
								<li>
										<p>从映射文件到Java源代码的生成器(也就是<tt class="literal">CodeGenerator</tt>，<tt class="literal">hbm2java</tt>） </p>
								</li>
								<li>
										<p>从已编译的Java类或者带有XDoclet标记的Java源代码生成映射文件（它们是<tt class="literal">MapGenerator</tt>,<tt class="literal">class2hbm</tt>） </p>
								</li>
						</ul>
				</div>
				<p>实际上Hibernate Extensions里面还有一个工具：<tt class="literal">ddl2hbm</tt>。但是它已经被废弃了，已经不再被维护了。Middlegen完成了同样的任务，并且更加出色。 </p>
				<p>对Hibernate提供支持的第三方工具有： </p>
				<div class="itemizedlist">
						<ul type="disc">
								<li>
										<p>Middlegen (从现有的数据库schema中生成映射文件） </p>
								</li>
								<li>
										<p>AndroMDA ( 使用MDA思想(Model-Driven Architecture ，模型驱动体系)的代码生成器，它从UML图和其XML/XMI等价形式中生成持久化类的代码） </p>
								</li>
						</ul>
				</div>
				<p>这些第三方工具没有在这篇指南中说明。请查阅Hibernate 网站得到关于它们目前的情况。（Hibernate主发行包中有关于整个网站的快照） </p>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="toolsetguide-s1">
														</a>15.1. Schema 生成器（Schema Generation）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>可以从你的映射文件使用一个命令行工具生成DDL。在Hibernate主发行包的<tt class="literal">hibernate-x.x.x/bin</tt>目录下有一个批处理文件。 </p>
						<p>生成的schema包含有对实体和集合类表的完整性引用约束（主键和外键）。涉及到的标示符生成器所需的表和sequence也会同时生成。 </p>
						<p>在使用这个工具的时候，你<span class="emphasis"><em>必须</em></span> 通过<tt class="literal">hibernate.dialet</tt>属性指定一个SQL<tt class="literal">方言(Dialet)</tt>。 </p>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="toolsetguide-s1-2">
																</a>15.1.1. 对schema定制化(Customizing the schema)</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>很多Hibernate映射元素定义了一个可选的<tt class="literal">length</tt>属性。你可以通过这个属性设置字段的长度。 (如果是Or, for numeric/decimal data types, the precision.) </p>
								<p>有些tag接受<tt class="literal">not-null</tt>属性（用来在表字段上生成<tt class="literal">NOT NULL</tt>约束）和<tt class="literal">unique</tt>属性（用来在表字段上生成<tt class="literal">UNIQUE</tt>约束）。 </p>
								<p>有些tag接受<tt class="literal">index</tt>属性，用来指定字段的index名字。<tt class="literal">unique-key</tt>属性可以对成组的字段指定一个组合键约束(unit key constraint)。目前，<tt class="literal">unique-key</tt>属性指定的值<span class="emphasis"><em>并不会</em></span>被当作这个约束的名字，它们只是在用来在映射文件内部用作区分的。 </p>
								<p>示例： </p>
								<pre class="programlisting">&lt;property name="foo" type="string" length="64" not-null="true"/&gt;

&lt;many-to-one name="bar" foreign-key="fk_foo_bar" not-null="true"/&gt;

&lt;element column="serial_number" type="long" not-null="true" unique="true"/&gt;</pre>
								<p>另外，这些元素还接受<tt class="literal">&lt;column&gt;</tt>子元素。在定义跨越多字段的类型时特别有用。 </p>
								<pre class="programlisting">&lt;property name="foo" type="string"&gt;
    &lt;column name="foo" length="64" not-null="true" sql-type="text"/&gt;
&lt;/property&gt;

&lt;property name="bar" type="my.customtypes.MultiColumnType"/&gt;
    &lt;column name="fee" not-null="true" index="bar_idx"/&gt;
    &lt;column name="fi" not-null="true" index="bar_idx"/&gt;
    &lt;column name="fo" not-null="true" index="bar_idx"/&gt;
&lt;/property&gt;</pre>
								<p>
										<tt class="literal">sql-type</tt>属性允许用户覆盖默认的Hibernate类型到SQL数据类型的映射。 </p>
								<p>
										<tt class="literal">check</tt>属性允许用户指定一个约束检查。 </p>
								<pre class="programlisting">&lt;property name="foo" type="integer"&gt;
    &lt;column name="foo" check="foo &gt; 10"/&gt;
&lt;/property&gt;

&lt;class name="Foo" table="foos" check="bar &lt; 100.0"&gt;
    ...
    &lt;property name="bar" type="float"/&gt;
&lt;/class&gt;</pre>
								<div class="table">
										<a name="schemattributes-summary">
										</a>
										<p class="title">
												<b>表 15.1. Summary</b>
										</p>
										<table summary="Summary" border="1">
												<colgroup>
														<col />
														<col />
												</colgroup>
												<thead>
														<tr>
																<th>属性(Attribute)</th>
																<th>值（Values）</th>
																<th>解释（Interpretation）</th>
														</tr>
												</thead>
												<tbody>
														<tr>
																<td>
																		<tt class="literal">length</tt>
																</td>
																<td>数字</td>
																<td>字段长度/小数点精度</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">not-null</tt>
																</td>
																<td>
																		<tt class="literal">true|false</tt>
																</td>
																<td>指明字段是否应该是非空的</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">unique</tt>
																</td>
																<td>
																		<tt class="literal">true|false</tt>
																</td>
																<td>指明是否该字段具有惟一约束</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">index</tt>
																</td>
																<td>
																		<tt class="literal">index_name</tt>
																</td>
																<td>指明一个（多字段）的索引(index)的名字</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">unique-key</tt>
																</td>
																<td>
																		<tt class="literal">unique_key_name</tt>
																</td>
																<td>指明多字段惟一约束的名字（参见上面的说明）</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">foreign-key</tt>
																</td>
																<td>
																		<tt class="literal">foreign_key_name</tt>
																</td>
																<td>指明一个外键的名字，它是为关联生成的。 </td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">sql-type</tt>
																</td>
																<td>
																		<tt class="literal">column_type</tt>
																</td>
																<td>覆盖默认的字段类型(只能用于<tt class="literal">&lt;column&gt;</tt>属性） </td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">check</tt>
																</td>
																<td>SQL 表达式</td>
																<td>对字段或表加入SQL约束检查 </td>
														</tr>
												</tbody>
										</table>
								</div>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="toolsetguide-s1-3">
																</a>15.1.2. 运行该工具</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>
										<tt class="literal">SchemaExport</tt>工具把DDL脚本写到标准输出，同时/或者执行DDL语句。 </p>
								<p>
										<tt class="literal">java -cp </tt>
										<span class="emphasis">
												<em>hibernate_classpaths</em>
										</span>
										<tt class="literal">net.sf.hibernate.tool.hbm2ddl.SchemaExport</tt>
										<span class="emphasis">
												<em>options mapping_files</em>
										</span>
								</p>
								<div class="table">
										<a name="d0e9256">
										</a>
										<p class="title">
												<b>表 15.2. <tt class="literal">SchemaExport</tt>命令行选项</b>
										</p>
										<table summary="SchemaExport命令行选项" border="1">
												<colgroup>
														<col />
														<col />
												</colgroup>
												<thead>
														<tr>
																<th>选项</th>
																<th>说明</th>
														</tr>
												</thead>
												<tbody>
														<tr>
																<td>
																		<tt class="literal">--quiet</tt>
																</td>
																<td>不要把脚本输出到stdout</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">--drop</tt>
																</td>
																<td>只进行drop tables的步骤</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">--text</tt>
																</td>
																<td>不执行在数据库中运行的步骤</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">--output=my_schema.ddl</tt>
																</td>
																<td>把输出的ddl脚本输出到一个文件</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">--config=hibernate.cfg.xml</tt>
																</td>
																<td>从XML文件读入Hibernate配置</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">--properties=hibernate.properties</tt>
																</td>
																<td>从文件读入数据库属性</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">--format</tt>
																</td>
																<td>把脚本中的SQL语句对齐和美化</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">--delimiter=x</tt>
																</td>
																<td>为脚本设置行结束符</td>
														</tr>
												</tbody>
										</table>
								</div>
								<p>你甚至可以在你的应用程序中嵌入<tt class="literal">SchemaExport</tt>工具: </p>
								<pre class="programlisting">Configuration cfg = ....;
new SchemaExport(cfg).create(false, true);</pre>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="toolsetguide-s1-4">
																</a>15.1.3. 属性(Properties)</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>可以通过如下方式指定数据库属性: </p>
								<div class="itemizedlist">
										<ul type="disc" compact="">
												<li>
														<p>通过<tt class="literal">-D</tt><span class="emphasis"><em>&lt;property&gt;</em></span>系统参数</p>
												</li>
												<li>
														<p>在<tt class="literal">hibernate.properties</tt>文件中</p>
												</li>
												<li>
														<p>位于一个其它名字的properties文件中,然后用 <tt class="literal">--properties</tt>参数指定</p>
												</li>
										</ul>
								</div>
								<p>所需的参数包括: </p>
								<div class="table">
										<a name="d0e9354">
										</a>
										<p class="title">
												<b>表 15.3. SchemaExport 连接属性</b>
										</p>
										<table summary="SchemaExport 连接属性" border="1">
												<colgroup>
														<col />
														<col />
												</colgroup>
												<thead>
														<tr>
																<th>属性名</th>
																<th>说明</th>
														</tr>
												</thead>
												<tbody>
														<tr>
																<td>
																		<tt class="literal">hibernate.connection.driver_class</tt>
																</td>
																<td>jdbc driver class</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">hibernate.connection.url</tt>
																</td>
																<td>jdbc url</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">hibernate.connection.username</tt>
																</td>
																<td>database user</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">hibernate.connection.password</tt>
																</td>
																<td>user password</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">hibernate.dialect</tt>
																</td>
																<td>方言(dialect)</td>
														</tr>
												</tbody>
										</table>
								</div>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="toolsetguide-s1-5">
																</a>15.1.4. 使用Ant(Using Ant)</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>你可以在你的Ant build脚本中调用<tt class="literal">SchemaExport</tt>: </p>
								<pre class="programlisting">&lt;target name="schemaexport"&gt;
    &lt;taskdef name="schemaexport"
        classname="net.sf.hibernate.tool.hbm2ddl.SchemaExportTask"
        classpathref="class.path"/&gt;
    
    &lt;schemaexport
        properties="hibernate.properties"
        quiet="no"
        text="no"
        drop="no"
        delimiter=";"
        output="schema-export.sql"&gt;
        &lt;fileset dir="src"&gt;
            &lt;include name="**/*.hbm.xml"/&gt;
        &lt;/fileset&gt;
    &lt;/schemaexport&gt;
&lt;/target&gt;</pre>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="toolsetguide-s1-6">
																</a>15.1.5. 对schema的增量更新(Incremental schema updates)</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>
										<tt class="literal">SchemaUpdate</tt>工具对已存在的schema采用"增量"方式进行更新。注意<tt class="literal">SchemaUpdate</tt>严重依赖于JDBC metadata API,所以它并非对所有JDBC驱动都有效。 </p>
								<p>
										<tt class="literal">java -cp </tt>
										<span class="emphasis">
												<em>hibernate_classpaths</em>
										</span>
										<tt class="literal">net.sf.hibernate.tool.hbm2ddl.SchemaUpdate</tt>
										<span class="emphasis">
												<em>options mapping_files</em>
										</span>
								</p>
								<div class="table">
										<a name="d0e9431">
										</a>
										<p class="title">
												<b>表 15.4. <tt class="literal">SchemaUpdate</tt>命令行选项</b>
										</p>
										<table summary="SchemaUpdate命令行选项" border="1">
												<colgroup>
														<col />
														<col />
												</colgroup>
												<thead>
														<tr>
																<th>选项</th>
																<th>说明</th>
														</tr>
												</thead>
												<tbody>
														<tr>
																<td>
																		<tt class="literal">--quiet</tt>
																</td>
																<td>不要把脚本输出到stdout</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">--properties=hibernate.properties</tt>
																</td>
																<td>从指定文件读入数据库属性</td>
														</tr>
												</tbody>
										</table>
								</div>
								<p>你可以在你的应用程序中嵌入<tt class="literal">SchemaUpdate</tt>工具: </p>
								<pre class="programlisting">Configuration cfg = ....;
new SchemaUpdate(cfg).execute(false);</pre>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="toolsetguide-s1-7">
																</a>15.1.6. 用Ant来增量更新schema(Using Ant for incremental schema updates)</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>你可以在Ant脚本中调用<tt class="literal">SchemaUpdate</tt>： </p>
								<pre class="programlisting">&lt;target name="schemaupdate"&gt;
    &lt;taskdef name="schemaupdate"
        classname="net.sf.hibernate.tool.hbm2ddl.SchemaUpdateTask"
        classpathref="class.path"/&gt;
    
    &lt;schemaupdate
        properties="hibernate.properties"
        quiet="no"&gt;
        &lt;fileset dir="src"&gt;
            &lt;include name="**/*.hbm.xml"/&gt;
        &lt;/fileset&gt;
    &lt;/schemaupdate&gt;
&lt;/target&gt;</pre>
						</div>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="toolsetguide-s2">
														</a>15.2. 代码生成（Code Generation）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>Hibernate代码生成器可以用来为Hibernate映射文件生成Java实现类的骨架。这个工具在Hibernate Extensions发行包中提供（需要单独下载）。 </p>
						<p>
								<tt class="literal">hbm2java</tt>解析映射文件，生成可工作的Java源代码文件。使用<tt class="literal">hbm2java</tt>，你可以“只”提供<tt class="literal">.hbm</tt>文件，不用担心要去手工编写Java文件。 </p>
						<p>
								<tt class="literal">java -cp</tt>
								<span class="emphasis">
										<em>hibernate_classpaths</em>
								</span>
								<tt class="literal">net.sf.hibernate.tool.hbm2java.CodeGenerator</tt>
								<span class="emphasis">
										<em>options mapping_files</em>
								</span>
						</p>
						<div class="table">
								<a name="d0e9505">
								</a>
								<p class="title">
										<b>表 15.5. 代码生成器命令行选项</b>
								</p>
								<table summary="代码生成器命令行选项" border="1">
										<colgroup>
												<col />
												<col />
										</colgroup>
										<thead>
												<tr>
														<th>选项</th>
														<th>说明</th>
												</tr>
										</thead>
										<tbody>
												<tr>
														<td>
																<tt class="literal">--output=</tt>
																<span class="emphasis">
																		<em>output_dir</em>
																</span>
														</td>
														<td>生成代码输出的根目录</td>
												</tr>
												<tr>
														<td>
																<tt class="literal">--config=</tt>
																<span class="emphasis">
																		<em>config_file</em>
																</span>
														</td>
														<td>可选的hvm2java配置文件</td>
												</tr>
										</tbody>
								</table>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="toolsetguide-s2-1">
																</a>15.2.1. 配置文件(可选)</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>配置文件提供了配置生成源代码的多个"渲染器(renders)"的途径,也可以声明在全局范围生效的<tt class="literal">&lt;meta&gt;</tt>属性。详情请参见<tt class="literal">&lt;meta&gt;</tt>属性的部分。 </p>
								<pre class="programlisting">&lt;codegen&gt;
    &lt;meta attribute="implements"&gt;codegen.test.IAuditable&lt;/meta&gt;
    &lt;generate renderer="net.sf.hibernate.tool.hbm2java.BasicRenderer"/&gt;
    &lt;generate
        package="autofinders.only"
        suffix="Finder"
        renderer="net.sf.hibernate.tool.hbm2java.FinderRenderer"/&gt;
&lt;/codegen&gt;</pre>
								<p>这个配置文件声明了一个全局的meta(元）属性“implements”，指定了两个渲染器，默认渲染器(BadicRender)和生成Finder（参见下面的“基本Finder 生成器”）的渲染器。 </p>
								<p>定义第二个渲染器需要一个包名和后缀属性。 </p>
								<p>包名属性指定生成后的源代码应该保存的位置，覆盖在<tt class="literal">.hbm</tt>文件中指定的包范围。 </p>
								<p>后缀属性指定生成的文件的后缀。比如说，如果有一个<tt class="literal">Foo.java</tt>文件，应该变成<tt class="literal">FooFinder.java</tt>。 </p>
								<p>也可以通过在<tt class="literal">&lt;generate&gt;</tt>元素上增加<tt class="literal">&lt;param&gt;</tt>属性来传递特别的参数到渲染器去。 </p>
								<p>hbm2java目前支持一个这样的参数，名字是<tt class="literal">generate-concrete-empty-classes</tt>来通知BasicRender对你所有的类都只生成空的具体类来继承它们。下列config.xml演示了这个功能 </p>
								<pre class="programlisting">            &lt;codegen&gt;
              &lt;generate prefix="Base" renderer="net.sf.hibernate.tool.hbm2java.BasicRenderer"/&gt; 
              &lt;generate renderer="net.sf.hibernate.tool.hbm2java.BasicRenderer"&gt;
                &lt;param name="generate-concrete-empty-classes"&gt;true&lt;/param&gt;
                &lt;param name="baseclass-prefix"&gt;Base&lt;/param&gt;
              &lt;/generate&gt;
            &lt;/codegen&gt;</pre>
								<p>注意，这个config.xml定义了两个渲染器。一个生成Base类，第二个只生成空的具体类。 </p>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="toolsetguide-s2-2">
																</a>15.2.2. <tt class="literal">meta</tt>属性</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>
										<tt class="literal">&lt;meta&gt;</tt>标签时对<tt class="literal">hbm.xml</tt>文件进行的简单注解，工具可以用这个位置来保存/阅读和Hibernate内核不是直接相关的一些信息。 </p>
								<p>你可以用<tt class="literal">&lt;meta&gt;</tt>标签来告诉<tt class="literal">hbm2java</tt>只生成"protectd" </p>
								<p>下面的例子： </p>
								<pre class="programlisting">&lt;class name="Person"&gt;
    &lt;meta attribute="class-description"&gt;
        Javadoc for the Person class
        @author Frodo
    &lt;/meta&gt;
    &lt;meta attribute="implements"&gt;IAuditable&lt;/meta&gt;
    &lt;id name="id" type="long"&gt;
        &lt;meta attribute="scope-set"&gt;protected&lt;/meta&gt;
        &lt;generator class="increment"/&gt;
    &lt;/id&gt;
    &lt;property name="name" type="string"&gt;
        &lt;meta attribute="field-description"&gt;The name of the person&lt;/meta&gt;
    &lt;/property&gt;
&lt;/class&gt;</pre>
								<p>会生成类似下面的输出（为了有助于理解，节选部分代码）。注意Javadoc注释和声明成protected的set方法： </p>
								<pre class="programlisting">// default package

import java.io.Serializable;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;

/** 
 *         Javadoc for the Person class
 *         @author Frodo
 *     
 */
public class Person implements Serializable, IAuditable {

    /** identifier field */
    public Long id;

    /** nullable persistent field */
    public String name;

    /** full constructor */
    public Person(java.lang.String name) {
        this.name = name;
    }

    /** default constructor */
    public Person() {
    }

    public java.lang.Long getId() {
        return this.id;
    }

    protected void setId(java.lang.Long id) {
        this.id = id;
    }

    /** 
     * The name of the person
     */
    public java.lang.String getName() {
        return this.name;
    }

    public void setName(java.lang.String name) {
        this.name = name;
    }

}</pre>
								<div class="table">
										<a name="d0e9610">
										</a>
										<p class="title">
												<b>表 15.6. 支持的meta标签</b>
										</p>
										<table summary="支持的meta标签" border="1">
												<colgroup>
														<col />
														<col />
												</colgroup>
												<thead>
														<tr>
																<th>属性</th>
																<th>说明</th>
														</tr>
												</thead>
												<tbody>
														<tr>
																<td>
																		<tt class="literal">class-description</tt>
																</td>
																<td>插入到类的javadoc说明去</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">field-description</tt>
																</td>
																<td>插入到field/property的javadoc说明去</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">interface</tt>
																</td>
																<td>如果是true,生成interface而非class</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">implements</tt>
																</td>
																<td>类要实现的接口</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">extends</tt>
																</td>
																<td>类要继承的超类(若是subclass,则忽略该属性)</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">generated-class</tt>
																</td>
																<td>重新指定要生成的类名</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">scope-class</tt>
																</td>
																<td>class的scope</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">scope-set</tt>
																</td>
																<td>set方法的scope</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">scope-get</tt>
																</td>
																<td>get方法的scope</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">scope-field</tt>
																</td>
																<td>实际属性字段(field)的scope</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">use-in-tostring</tt>
																</td>
																<td>在<tt class="literal">toString()</tt>中包含此属性</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">implement-equals</tt>
																</td>
																<td>在这个类中包含<tt class="literal">equals()</tt>和<tt class="literal">hashCode()</tt>方法</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">use-in-equals</tt>
																</td>
																<td>在<tt class="literal">equals()</tt>和<tt class="literal">hashCode()</tt> 方法中包含此属性</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">bound</tt>
																</td>
																<td>为属性增加propertyChangeListener支持</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">constrained</tt>
																</td>
																<td>为属性增加vetoChangeListener支持</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">gen-property</tt>
																</td>
																<td>如果是false,不会生成属性(谨慎使用)</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">property-type</tt>
																</td>
																<td>覆盖属性的默认值.如果值是标签,则指定一个具体的类型而非Object(Use this with any tag's to specify the concrete type instead of just Object.)</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">class-code</tt>
																</td>
																<td>在类的最后会插入的额外代码</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">extra-import</tt>
																</td>
																<td>在所有的import后面会插入的额外的import</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">finder-method</tt>
																</td>
																<td>参见下面的"Basic finder generator"</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">session-method</tt>
																</td>
																<td>参见下面的"Basic finder generator"</td>
														</tr>
												</tbody>
										</table>
								</div>
								<p>通过<tt class="literal">&lt;meta&gt;</tt>标签定义的属性在一个<tt class="literal">hbm.xml</tt>文件中是默认"继承"的。 </p>
								<p>这究竟是什么意思？如果你希望你所有的类都实现<tt class="literal">IAuditable</tt>接口，那么你只需要加一个<tt class="literal">&lt;meta attribute="implements"&gt;IAuditable&lt;/meta&gt;</tt> 在你<tt class="literal">hml.xml</tt>文件的开头，就在<tt class="literal">&lt;hibernate-mapping&gt;</tt>后面。现在所有在<tt class="literal">hbm.xml</tt>文件中定义的类都会实现<tt class="literal">IAuditable</tt>了！（除了那些也特别指定了"implements"元属性的类，因为本地指定的元标签总是会覆盖任何继承的元标签）。 </p>
								<p>注意，这条规则对<span class="emphasis"><em>所有</em></span> 的<tt class="literal">&lt;meta&gt;</tt>标签都有效。也就是说它可以用来指定所有的字段都被声明成protected的，而非默认的private。这可以通过在<tt class="literal">&lt;class&gt;</tt>后面<tt class="literal">&lt;meta attribute="scope-field"&gt;protected&lt;/meta&gt;</tt>指定，那么这个类所有的field都会变成protected。 </p>
								<p>如果你不想让<tt class="literal">&lt;meta&gt;</tt>标签继承，你可以简单的在标签属性上指明<tt class="literal">inherit="false"</tt>，比如<tt class="literal">&lt;meta attribute="scope-class" inherit="false"&gt;public abstract&lt;/meta&gt;</tt>，这样"class-scope"就只会对当前类起作用，不会对其子类生效。 </p>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="toolsetguide-s2-3">
																</a>15.2.3. 基本的finder生成器（Basic finder generator）</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>目前可以让<tt class="literal">hbm2java</tt>为Hibernate属性生成基本的finder。这需要在<tt class="literal">hbm.xml</tt>文件中做两件事情。 </p>
								<p>首先是要标记出你希望生成finder的字段。你可以通过在property标签中的meta 块来定义： </p>
								<pre class="programlisting">&lt;property name="name" column="name" type="string"&gt;
     &lt;meta attribute="finder-method"&gt;findByName&lt;/meta&gt;
&lt;/property&gt;</pre>
								<p>find方法的名字就是meta标签中间的文字。 </p>
								<p>第二件事是为hbm2java建立下面格式的配置文件： </p>
								<pre class="programlisting">&lt;codegen&gt;
    &lt;generate renderer="net.sf.hibernate.tool.hbm2java.BasicRenderer"/&gt;
    &lt;generate suffix="Finder" renderer="net.sf.hibernate.tool.hbm2java.FinderRenderer"/&gt;
&lt;/codegen&gt;</pre>
								<p>然后用参数去调用：<tt class="literal">hbm2java --config=xxx.xml</tt>，<tt class="literal">xxx.xml</tt>就是你刚才创建的配置文件的名字。 </p>
								<p>有个可选的参数,作为一个在class级别的meta标签，格式如下： </p>
								<pre class="programlisting">&lt;meta attribute="session-method"&gt;
    com.whatever.SessionTable.getSessionTable().getSession();
&lt;/meta&gt;</pre>
								<p>他是用来管理你如何使用<span class="emphasis"><em>Thread Local Session</em></span>模式(在Hibernate 网站的Design Patterns部分有文档）得到session的。 </p>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="toolsetguide-s2-4">
																</a>15.2.4. 基于Velocity的渲染器/生成器(Velocity based renderer/generator)</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>目前可以使用velocity作为渲染机制的一个替代方案。下面的config.xml文件显示了如果配置hbm2java来使用velocity渲染器。 </p>
								<pre class="programlisting">    &lt;codegen&gt;
     &lt;generate renderer="net.sf.hibernate.tool.hbm2java.VelocityRenderer"&gt;
      &lt;param name="template"&gt;pojo.vm&lt;/param&gt;
     &lt;/generate&gt;
    &lt;/codegen&gt;</pre>
								<p>名为<tt class="literal">template</tt>的参数是指向你希望你使用velocity macro文件的资源路径。这个文件必须在hbm2java的classpath中。所以要记住把pojo.vm所在的路径加入到你ant任务或者shell脚本中去。（默认的位置是<tt class="literal">./tools/src/velocity</tt>) </p>
								<p>注意，当前的<tt class="literal">pojo.vm</tt>只生成java beans最基本的部分。他还没有默认的渲染器那么完整，也没有那么多功能——特别是大部分<tt class="literal">meta</tt>标签还不支持。 </p>
						</div>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="toolsetguide-s3">
														</a>15.3. 映射文件生成器（Mapping File Generation）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>映射文件的骨架可以从编译过的持久化类中使用<tt class="literal">MapGenerator</tt>工具生成。这工具是Hibernate Extensions发行包的一部分。 </p>
						<p>Hibernate映射生成器提供了从编译过的类中产生映射的机制。他使用Java反射来查找<span class="emphasis"><em>属性( properties)</em></span>，然后使用启发式算法来从属性类型猜测合适的映射。生成出来的映射文件之应该看作是后续工作的起点。没有办法在没有用户修正的情况下生成完整的Hibernate映射。但是，这个工具还是替你做了很多非常琐碎和麻烦的工作。 </p>
						<p>类一个一个地加入到映射去。如果工具认为某个类不是<span class="emphasis"><em>Hibernate可持久化（ persistable）</em></span>的，就会把这些类剔除。 </p>
						<p>判断是否是<span class="emphasis"><em>Hibernate可持久化（ persistable）</em></span>的原则是： </p>
						<div class="itemizedlist">
								<ul type="disc" compact="">
										<li>
												<p>必定不是一个原始类型</p>
										</li>
										<li>
												<p>必定不是一个数组</p>
										</li>
										<li>
												<p>必定不是一个接口</p>
										</li>
										<li>
												<p>必定不是一个内部类</p>
										</li>
										<li>
												<p>必定有一个默认的无参数的构造方法。</p>
										</li>
								</ul>
						</div>
						<p>注意，接口和内部类实际上是可以通过Hibernate持久化的，但是一般来说用户不会使用。 </p>
						<p>对已经发现的类，<tt class="literal">MapGenerator</tt>会重复回溯到超类链条上去，以尽可能的把Hibernate可持久化的超类加入到对同一个数据库表的映射去。如果回溯过程中某个类出现了有个属性在下列<span class="emphasis"><em>备选UID名字（candidate UID names）</em></span>名单中，回溯就会停止。 </p>
						<p>默认的备选UID属性名有：<tt class="literal">uid</tt>, <tt class="literal">UID</tt>, <tt class="literal">id</tt>, <tt class="literal">ID</tt>, <tt class="literal">key</tt>, <tt class="literal">KEY</tt>, <tt class="literal">pk</tt>, <tt class="literal">PK</tt>。 </p>
						<p>如果类中有两个方法，一个是setter,一个是getter，并且setter的单参数的属性和getter的无参数返回值得类型相同，并且setter返回<tt class="literal">void</tt>,就认为发现了一个属性。并且，setter的名字必须以<tt class="literal">set</tt>字符串开始，getter的名字必须以<tt class="literal">get</tt>开始，或者以<tt class="literal">is</tt>开始并且属性类型是boolean。在上面的情况发生时，get和set之后的名字还必须匹配。这个匹配就是属性的名字，然后如果第二个字母是小写的话，会把其首字母变成小写。 </p>
						<p>用来决定每个属性的数据库类型的规则如下： </p>
						<div class="orderedlist">
								<ol type="1" compact="">
										<li>
												<p>如果Java类型是<tt class="literal">Hibernate.basic()</tt>，则属性是该类型的一个普通字段。 </p>
										</li>
										<li>
												<p>对于<tt class="literal">hibernate.type.Type</tt>特定类型和<tt class="literal">PersistentEnum</tt>来说，也会使用一个普通字段。 </p>
										</li>
										<li>
												<p>如果属性类型是一个数组，那么会使用一个Hibernate数组,并且<tt class="literal">MapGenerator</tt>试图反映数组元素的类型。（attempts to reflect on the array element type.） </p>
										</li>
										<li>
												<p>如果属性是<tt class="literal">java.util.List</tt>,<tt class="literal">java.util.Map</tt>或者<tt class="literal">java.util.Set</tt>，会使用对应的Hibernate类型，但是<tt class="literal">MapGenerator</tt>不能对这些类型进行进一步处理了。 </p>
										</li>
										<li>
												<p>如果属性的类型不是上面任何一种，<tt class="literal">MapGeneraotr</tt>把决定数据库类型的步骤留待所有的类都被处理之后再来做。在那时候，如果类在上面描述过的超类搜索过程中被发现了，这个属性会被认为是一个<tt class="literal">many-to-one</tt>的关联。如果类有人和属性，它则是一个<tt class="literal">组件(component)</tt>。否则它就是可序列化的（serializable），或者不是可持久化的。 </p>
										</li>
								</ol>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="toolsetguide-s3-1">
																</a>15.3.1. 运行此工具</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>这个工具会把XML映射写入到标准输出或者/并且到一个文件中去。 </p>
								<p>在调用这个工具的时候，你必须把你编译过的类放到classpath中去。 </p>
								<p>
										<tt class="literal">java -cp </tt>
										<span class="emphasis">
												<em>hibernate_and_your_class_classpaths</em>
										</span>
										<tt class="literal">net.sf.hibernate.tool.class2hbm.MapGenerator</tt>
										<span class="emphasis">
												<em>options and classnames</em>
										</span>
								</p>
								<p>有两种操作模式：命令行或者交互式。 </p>
								<p>交互式模式当你使用一个惟一的命令行参数<tt class="literal">--interact</tt>的时候启动。这个模式提供一个命令控制台。你可以用<tt class="literal">uid=XXX</tt>命令设置每个类的UID属性的名字，<tt class="literal">XXX</tt>就是UID属性名。其他可用的命令就是类名的全限定名，或者“done”命令用来输出XML,并且结束。 </p>
								<p>在命令行模式下，下面的参数选项和所需处理的类的全限定名可以相互间隔使用。大多数选项会使用多次，每个只影响其后出现的类。 </p>
								<div class="table">
										<a name="d0e10053">
										</a>
										<p class="title">
												<b>表 15.7. MapGenerator命令行选项</b>
										</p>
										<table summary="MapGenerator命令行选项" border="1">
												<colgroup>
														<col />
														<col />
												</colgroup>
												<thead>
														<tr>
																<th>选项</th>
																<th>说明</th>
														</tr>
												</thead>
												<tbody>
														<tr>
																<td>
																		<tt class="literal">--quiet</tt>
																</td>
																<td>不把O-R 映射输出到stdout</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">--setUID=uid</tt>
																</td>
																<td>设置备选UID名单</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">--addUID=uid</tt>
																</td>
																<td>在备选UID名单前面增加一个新的uid</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">--select=</tt>
																		<span class="emphasis">
																				<em>mode</em>
																		</span>
																</td>
																<td>对后面的classes使用select选择的<span class="emphasis"><em>模式(mode)</em></span>(比如, <span class="emphasis"><em>distinct</em></span> 或者<span class="emphasis"><em>all</em></span>)</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">--depth=&lt;small-int&gt;</tt>
																</td>
																<td>限制后面的类的组件数据递归层数</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">--output=my_mapping.xml</tt>
																</td>
																<td>把O-R 映射输出到一个文件</td>
														</tr>
														<tr>
																<td>
																		<span class="emphasis">
																				<em>full.class.Name</em>
																		</span>
																</td>
																<td>把这个类加入到映射中</td>
														</tr>
														<tr>
																<td>
																		<tt class="literal">--abstract=</tt>
																		<span class="emphasis">
																				<em>full.class.Name</em>
																		</span>
																</td>
																<td>参见下面的说明</td>
														</tr>
												</tbody>
										</table>
								</div>
								<p>abstract开关指定本工具忽略特定的超类,所以它的继承数上的类不会被映射到一个大表中去。比如，我们来看下面的类继承树： </p>
								<p>
										<tt class="literal">Animal--&gt;Mammal--&gt;Human</tt>
								</p>
								<p>
										<tt class="literal">Animal--&gt;Mammal--&gt;Marsupial--&gt;Kangaroo</tt>
								</p>
								<p>如果<span class="emphasis"><em>不</em></span>使用<tt class="literal">--abstract</tt>开关，<tt class="literal">Animal</tt>的所有子类都会被放到一个巨大的表中去，包含所有类的所有属性，还有一个用于分辨子类的字段。如果<tt class="literal">Mammal</tt>被标记成<tt class="literal">abstract</tt>，<tt class="literal">Human</tt>和<tt class="literal">Marsupial</tt>会被映射到不同的<tt class="literal">&lt;class&gt;</tt>声明，并且会有各自单独的表。<tt class="literal">Kangaroo</tt>仍然会被认为是<tt class="literal">Marsupial</tt>的子类，除非<tt class="literal">Marsupial</tt>也标记为<tt class="literal">anstract</tt>的。 </p>
						</div>
				</div>
		</div>
		<div class="navfooter">
				<hr />
				<table width="100%" summary="Navigation footer">
						<tbody>
								<tr>
										<td align="left" width="40%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/performance.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<td align="middle" width="20%">
												<a accesskey="u" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">上一级</font>
												</a>
										</td>
										<td align="right" width="40%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/example-parentchild.html"><font color="#002c99">下一页</font></a></td>
								</tr>
								<tr>
										<td valign="top" align="left" width="40%">第 14 章 性能提升（Improving performance） </td>
										<td align="middle" width="20%">
												<a accesskey="h" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">起始页</font>
												</a>
										</td>
										<td valign="top" align="right" width="40%"> 第 16 章 示例：父子关系(Parent Child Relationships)</td>
								</tr>
						</tbody>
				</table>
		</div>
<img src ="http://www.cnitblog.com/forrest/aggbug/16234.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2006-08-31 18:42 <a href="http://www.cnitblog.com/forrest/articles/16234.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第 13 章 原生SQL查询 第 14 章 性能提升（Improving performance）</title><link>http://www.cnitblog.com/forrest/articles/16233.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Thu, 31 Aug 2006 10:41:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/articles/16233.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/16233.html</wfw:comment><comments>http://www.cnitblog.com/forrest/articles/16233.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/16233.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/16233.html</trackback:ping><description><![CDATA[
		<div class="navheader">
				<table width="100%" summary="Navigation header">
						<tbody>
								<tr>
										<th align="middle" colspan="3">第 13 章 原生SQL查询</th>
								</tr>
								<tr>
										<td align="left" width="20%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/querycriteria.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<th align="middle" width="60%"> </th>
										<td align="right" width="20%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/performance.html"><font color="#002c99">下一页</font></a></td>
								</tr>
						</tbody>
				</table>
				<font color="#002c99">
						<hr />
				</font>
		</div>
		<div class="chapter" lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h2 class="title">
												<a name="querysql">
												</a>第 13 章 原生SQL查询</h2>
								</div>
						</div>
						<div>
						</div>
				</div>
				<p>你也可以直接使用你的数据库方言表达查询。在你想使用数据库的某些特性的时候，这是非常有用的， 比如Oracle中的CONNECT关键字。这也会扫清你把原来直接使用SQL/JDBC 的程序移植到Hibernate道路上的障碍。 </p>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="querysql-creating">
														</a>13.1. 创建一个基于SQL的<tt class="literal">Query</tt></h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>和普通的HQL查询一样，SQL查询同样是从<tt class="literal">Query</tt>接口开始的。惟一的区别是使用<tt class="literal">Session.createSQLQuery()</tt>方法。 </p>
						<pre class="programlisting">Query sqlQuery = sess.createSQLQuery("select {cat.*} from cats {cat}", "cat", Cat.class);
sqlQuery.setMaxResults(50);
List cats = sqlQuery.list();</pre>
						<p>传递给<tt class="literal">createSQLQuer()</tt>的三个参数是： </p>
						<div class="itemizedlist">
								<ul type="disc">
										<li>
												<p>SQL查询语句 </p>
										</li>
										<li>
												<p>表的别名 </p>
										</li>
										<li>
												<p>查询返回的持久化类 </p>
										</li>
								</ul>
						</div>
						<p>别名是为了在SQL语句中引用对应的类（本例中是<tt class="literal">Cat</tt>)的属性的。你也可以传递一个别名的<tt class="literal">String</tt> 数组和一个对应的<tt class="literal">Class</tt>的数组进去，每行就可以得到多个对象。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="querysql-aliasreferences">
														</a>13.2. 别名和属性引用</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>上面使用的<tt class="literal">{cat.*}</tt>标记是“所有属性的”的简写。你可以显式的列出需要的属性，但是你必须让Hibernate为每个 属性提供SQL列别名。这些列的的占位表示符是以表别名为前导，再加上属性名。下面的例子中，我们从一个其它的表(<tt class="literal">cat_log</tt>) 中获取<tt class="literal">Cat</tt>对象，而非<tt class="literal">Cat</tt>对象原本在映射元数据中声明的表。注意你在where子句中也可以使用 属性别名。 </p>
						<pre class="programlisting">String sql = "select cat.originalId as {cat.id}, "
    + "  cat.mateid as {cat.mate}, cat.sex as {cat.sex}, "
    + "  cat.weight*10 as {cat.weight}, cat.name as {cat.name}"
    + "     from cat_log cat where {cat.mate} = :catId"
List loggedCats = sess.createSQLQuery(sql, "cat", Cat.class)
    .setLong("catId", catId)
    .list();
</pre>
						<p>
								<span class="emphasis">
										<em>注意：</em>
								</span> 如果你明确的列出了每个属性，你必须包含这个类<span class="emphasis"><em>和它的子类</em></span>的属性! //?? </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="querysql-namedqueries">
														</a>13.3. 为SQL查询命名</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>可以在映射文档中定义SQL查询的名字，然后就可以像调用一个命名HQL查询一样直接调用命名SQL查询。 </p>
						<pre class="programlisting">&lt;sql-query name="mySqlQuery"&gt;
    &lt;return alias="person" class="eg.Person"/&gt;
    SELECT {person}.NAME AS {person.name},
           {person}.AGE AS {person.age},
           {person}.SEX AS {person.sex}
    FROM PERSON {person} WHERE {person}.NAME LIKE 'Hiber%'
&lt;/sql-query&gt;</pre>
				</div>
		</div>
		<div class="navfooter">
				<hr />
				<table width="100%" summary="Navigation footer">
						<tbody>
								<tr>
										<td align="left" width="40%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/querycriteria.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<td align="middle" width="20%">
												<a accesskey="u" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">上一级</font>
												</a>
										</td>
										<td align="right" width="40%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/performance.html"><font color="#002c99">下一页</font></a></td>
								</tr>
								<tr>
										<td valign="top" align="left" width="40%">第 12 章 条件查询(Criteria Query) </td>
										<td align="middle" width="20%">
												<a accesskey="h" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">起始页</font>
												</a>
										</td>
										<td valign="top" align="right" width="40%"> 第 14 章 性能提升（Improving performance）<br /><br /></td>
								</tr>
						</tbody>
				</table>
		</div>
		<div class="navheader">
				<table width="100%" summary="Navigation header">
						<tbody>
								<tr>
										<th align="middle" colspan="3">第 14 章 性能提升（Improving performance）</th>
								</tr>
								<tr>
										<td align="left" width="20%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/querysql.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<th align="middle" width="60%"> </th>
										<td align="right" width="20%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/toolsetguide.html"><font color="#002c99">下一页</font></a></td>
								</tr>
						</tbody>
				</table>
				<font color="#002c99">
						<hr />
				</font>
		</div>
		<div class="chapter" lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h2 class="title">
												<a name="performance">
												</a>第 14 章 性能提升（Improving performance）</h2>
								</div>
						</div>
						<div>
						</div>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="performance-collections">
														</a>14.1. 理解集合的性能</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>我们已经花了很长时间在讨论集合(collections)了。在本章，我们会特别关注一些关于集合在运行时如何运作的问题。 </p>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="performance-collections-taxonomy">
																</a>14.1.1. 分类</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>Hibernate定义了三种基本类型的集合：</p>
								<div class="itemizedlist">
										<ul type="disc">
												<li>
														<p>值集合</p>
												</li>
												<li>
														<p>一对多关联</p>
												</li>
												<li>
														<p>多对多关联</p>
												</li>
										</ul>
								</div>
								<p>这个分类是按照不同的表和外键关系类型来区分的，但是没有告诉我们关于关系模型的一切。要完全理解他们的关系结构和性能特点，我们必须思考用于更新或删除集合行的主键的结构。这得到了如下的分类： </p>
								<div class="itemizedlist">
										<ul type="disc">
												<li>
														<p>有序集合类</p>
												</li>
												<li>
														<p>集合（sets）</p>
												</li>
												<li>
														<p>包（bags）</p>
												</li>
										</ul>
								</div>
								<p>有序集合类（maps, lists, arrays)有一个包含有<tt class="literal">&lt;key&gt;</tt>和<tt class="literal">&lt;index&gt;</tt>字段的主键。这种情况下集合类更新是特别高效的——主键会有效索引，当Hibernate试图更新或删除一行时，可以迅速找到这一行。 </p>
								<p>集合(sets)的主键包含有 <tt class="literal">&lt;key&gt;</tt> 和元素字段。对于有些元素类型来说，这会变得低效，特别是组合元素或者大文本、大二进制字段；数据库可能无法有效对复杂的主键进行索引。另一方面，对于一对多或多对多关联，特别是合成的标识符来说，它会达到同样的高效。（附注：如果你希望<tt class="literal">SchemaExport</tt>为你的<tt class="literal">&lt;set&gt;</tt>创建主键，你必须把所有的字段都声明为<tt class="literal">not-null="true"</tt>。） </p>
								<p>Bag是最差的。因为bag允许重复的元素值，也没有索引字段，不可能定义主键。Hibernate没有办法来判断出重复的行。每当这种集合被更改，Hibernate会完整地移除（通过一个<tt class="literal">DELETE</tt>）,再重建整个集合。这会非常低效。 </p>
								<p>请注意对一对多关联来说，“主键”可能是数据库表的物理主键——但就算在这种情况下，上面的分类仍然是有用的。（它会反映Hibernate是如何在集合的各个行中“定位”的。） </p>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="performance-collections-mostefficientupdate">
																</a>14.1.2. Lists, maps 和sets用于更新效率最高</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>根据我们上面的讨论，显然有序类型和大多数set可以在增加/删除/修改元素的时候得到最好的性能。 </p>
								<p>但是，在多对多关联，或者对值元素而言，有序集合类比集合(set)有一个好处。因为<tt class="literal">Set</tt>的结构，如果“改变”了一个元素,Hibernate并不会<tt class="literal">UPDATE</tt>这一行。对<tt class="literal">Set</tt>来说，只有<tt class="literal">INSERT</tt>和<tt class="literal">DELETE</tt>才有效。注意这一段描述对一对多关联并不适用。 </p>
								<p>注意到数组无法延迟转载，我们可以得出结论，list, map和set是最高效的集合类型。（当然，我们警告过了，由于集合中的值的关系，set可能性能下降。） </p>
								<p>Set可以被看作是Hibernate程序中最普遍的集合类型。 </p>
								<p>
										<span class="emphasis">
												<em>这个版本的Hibernate有一个没有写在文档中的功能。<tt class="literal">&lt;idbag&gt;</tt>可以对值集合和多对多关联实现bag语义，并且性能比上面任何类型都高！</em>
										</span>
								</p>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="performance-collections-mostefficentinverse">
																</a>14.1.3. Bag和list是反向集合类中效率最高的</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>好了，在你把bag扔到水沟里面再踩上一只脚之前要了解，有一种情况下bag(包括list)要比set性能高得多。对于指明了<tt class="literal">inverse="true"</tt>的集合类（比如说，标准的双向一对多关联），我们可以在不初始化(fetch)包元素的情况下就增加新元素！这是因为<tt class="literal">Collection.add()</tt>或者<tt class="literal">Collection.addAll()</tt>对bag或者<tt class="literal">List</tt>总是返回true的（与<tt class="literal">Set</tt>不同）。对于下面的代码来说，速度会快得多。 </p>
								<pre class="programlisting">Parent p = (Parent) sess.load(Parent.class, id);
    Child c = new Child();
    c.setParent(p);
    p.getChildren().add(c);  //no need to fetch the collection!
    sess.flush();</pre>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="performance-collections-oneshotdelete">
																</a>14.1.4. 一次性删除(One shot delete)</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>有时候，一个一个的删除集合类中的元素是极度低效的。Hibernate没那么笨，如果你想要把整个集合都删除（比如说调用<tt class="literal">list.clear()</tt>），Hibernate只需要一个<tt class="literal">DELETE</tt>就搞定了。 </p>
								<p>假设我们在一个长度为20的集合类中新增加了一个元素，然后删除了两个。Hibernate会安排一个<tt class="literal">INSERT</tt>语句和两条<tt class="literal">DELETE</tt>语句（除非集合类是一个bag)。这当然是可以想见的。 </p>
								<p>但是，如果假设我们删除了18个元素，只剩下2个，然后新增3个。有两种处理方式： </p>
								<div class="itemizedlist">
										<ul type="disc">
												<li>
														<p>把这18个元素一个一个的干掉，再新增三个</p>
												</li>
												<li>
														<p>把整个集合类都咔嚓掉（只用一句<tt class="literal">DELETE</tt>语句），然后增加5个元素。 </p>
												</li>
										</ul>
								</div>
								<p>Hibernate还没那么聪明，知道第二种选择可能会比较快。（也许让Hibernate不要这么聪明也是好事，否则可能会引发意外的数据库触发器什么的。） </p>
								<p>幸运的是，你可以强制使用第二种策略。你需要把原来的整个集合类都取消（取消其引用），然后返回一个新实例化的集合类，只包含需要的元素。有些时候这是非常有用的。 </p>
						</div>
				</div>
				<p>我们已经为您展示了如何在对集合持久化时使用延迟装载（lazy initialization）。对于通常的对象引用，使用CGLIB代理可以达到类似的效果。我们也提到过Hibernate在<tt class="literal">Session</tt>级别缓存持久化对象。还有更多先进的缓存策略，你可以为每一个类单独配置。 </p>
				<p>这本章里，我们来教你如何使用这些特性，在必要的时候得到高得多的性能。 </p>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="performance-proxies">
														</a>14.2. 用于延迟装载的代理</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>Hibernate使用动态字节码增强技术来实现持久化对象的延迟装载代理（使用优秀的CGLIB库）。 </p>
						<p>映射文件为每一个类声明一个类或者接口作为代理接口。建议使用这个类自身： </p>
						<pre class="programlisting">&lt;class name="eg.Order" proxy="eg.Order"&gt;</pre>
						<p>运行时的代理应该是<tt class="literal">Order</tt>的子类。注意被代理的类必须实现一个默认的构造器，并且至少在包内可见。 </p>
						<p>在扩展这种方法来对应多形的类时，要注意一些细节,比如： </p>
						<pre class="programlisting">&lt;class name="eg.Cat" proxy="eg.Cat"&gt;
    ......
    &lt;subclass name="eg.DomesticCat" proxy="eg.DomesticCat"&gt;
        .....
    &lt;/subclass&gt;
&lt;/class&gt;</pre>
						<p>首先，<tt class="literal">Cat</tt>永远不能被强制转换为<tt class="literal">DomesticCat</tt>,即使实际上该实例就是一个<tt class="literal">DomesticCat</tt>实例。 </p>
						<pre class="programlisting">Cat cat = (Cat) session.load(Cat.class, id);  // instantiate a proxy (does not hit the db)
if ( cat.isDomesticCat() ) {                  // hit the db to initialize the proxy
    DomesticCat dc = (DomesticCat) cat;       // Error!
    ....
}</pre>
						<p>其次，代理的<tt class="literal">==</tt>可能不再成立。 </p>
						<pre class="programlisting">Cat cat = (Cat) session.load(Cat.class, id);            // instantiate a Cat proxy
DomesticCat dc = 
    (DomesticCat) session.load(DomesticCat.class, id);  // required new DomesticCat proxy!
System.out.println(cat==dc);                            // false</pre>
						<p>虽然如此，这种情况并不像看上去得那么糟。虽然我们现在有两个不同的引用来指向不同的代理对象，实际上底层的实例应该是同一个对象： </p>
						<pre class="programlisting">cat.setWeight(11.0);  // hit the db to initialize the proxy
System.out.println( dc.getWeight() );  // 11.0</pre>
						<p>第三，你不能对<tt class="literal">final</tt>的类或者具有<tt class="literal">final</tt>方法的类使用CGLIB代理。 </p>
						<p>最后,假如你的持久化对象在实例化的时候需要某些资源（比如，在实例化方法或者默认构造方法中），这些资源也会被代理需要。代理类实际上是持久化类的子类。 </p>
						<p>这些问题都来源于Java的单根继承模型的天生限制。如果你希望避免这些问题，你的每个持久化类必须抽象出一个接口，声明商业逻辑方法。你应该在映射文件中指定这些接口，比如： </p>
						<pre class="programlisting">&lt;class name="eg.Cat" proxy="eg.ICat"&gt;
    ......
    &lt;subclass name="eg.DomesticCat" proxy="eg.IDomesticCat"&gt;
        .....
    &lt;/subclass&gt;
&lt;/class&gt;</pre>
						<p>这里<tt class="literal">Cat</tt>实现<tt class="literal">ICat</tt>接口，并且<tt class="literal">DomesticCat</tt>实现<tt class="literal">IDomesticCat</tt>接口。于是 <tt class="literal">load()</tt>或者<tt class="literal">iterate()</tt>就会返回<tt class="literal">Cat</tt>和<tt class="literal">DomesticCat</tt>的实例的代理。(注意<tt class="literal">find()</tt>不会返回代理。) </p>
						<pre class="programlisting">ICat cat = (ICat) session.load(Cat.class, catid);
Iterator iter = session.iterate("from cat in class eg.Cat where cat.name='fritz'");
ICat fritz = (ICat) iter.next();</pre>
						<p>关系也是延迟装载的。这意味着你必须把任何属性声明为<tt class="literal">ICat</tt>类型，而非<tt class="literal">Cat</tt>。 </p>
						<p>某些特定操作<span class="emphasis"><em>不</em></span>需要初始化代理 </p>
						<div class="itemizedlist">
								<ul type="disc" compact="">
										<li>
												<p>
														<tt class="literal">equals()</tt>, 假如持久化类没有重载<tt class="literal">equals()</tt></p>
										</li>
										<li>
												<p>
														<tt class="literal">hashCode()</tt>, 假如持久化类没有重载<tt class="literal">hashCode()</tt></p>
										</li>
										<li>
												<p>标识符的get方法 </p>
										</li>
								</ul>
						</div>
						<p>Hibernate会识别出重载了<tt class="literal">equals()</tt> 或者 <tt class="literal">hashCode()</tt>方法的持久化类。 </p>
						<p>在初始化代理的时候发生的异常会被包装成<tt class="literal">LazyInitializationException</tt>。 </p>
						<p>有时候我们需要保证在<tt class="literal">Session</tt>关闭前某个代理或者集合已经被初始化了。当然，我们总是可以通过调用<tt class="literal">cat.getSex()</tt>或者 <tt class="literal">cat.getKittens().size()</tt>之类的方法来确保这一点。但是这样程序可读性不佳，也不符合通常的代码规范。静态方法<tt class="literal">Hibernate.initialize()</tt>和<tt class="literal">Hibernate.isInitialized()</tt>给你的应用程序一个正常的途径来加载集合或代理。<tt class="literal">Hibernate.initialize(cat)</tt> 会强制初始化一个代理,<tt class="literal">cat</tt>,只要它的<tt class="literal">Session</tt>仍然打开。<tt class="literal">Hibernate.initialize( cat.getKittens() )</tt>对kittens的集合具有同样的功能。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="performance-cache">
														</a>14.3. 第二层缓存(The Second Level Cache)s</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>Hibernate<tt class="literal">Session</tt>是事务级别的持久化数据缓存。再为每个类或者每个集合配置一个集群或者JVM级别(<tt class="literal">SessionFactory</tt>级别)的缓存也是有可能的。你甚至可以插入一个集群的缓存。要小心，缓存永远不会知道其他进程可能对持久化仓库（数据库）进行的修改（即使他们可能设定为经常对缓存的数据进行失效）。 </p>
						<p>默认情况下，Hibernate使用EHCache进行JVM级别的缓存。但是，对JCS的支持现在已经被废弃了，未来版本的Hibernate将会去掉它。通过<tt class="literal">hibernate.cache.provider_class</tt>属性，你也可以指定其他缓存，只要其实现了<tt class="literal">net.sf.hibernate.cache.CacheProvider</tt>接口。 </p>
						<div class="table">
								<a name="d0e8649">
								</a>
								<p class="title">
										<b>表 14.1. Cache Providers</b>
								</p>
								<table summary="Cache Providers" border="1">
										<colgroup>
												<col align="left" />
												<col align="left" />
												<col align="left" />
												<col align="left" />
												<col align="left" />
										</colgroup>
										<thead>
												<tr>
														<th align="left">Cache</th>
														<th align="left">Provider class</th>
														<th align="left">Type</th>
														<th align="left">Cluster Safe</th>
														<th align="left">Query Cache Supported</th>
												</tr>
										</thead>
										<tbody>
												<tr>
														<td align="left">Hashtable (not intended for production use)</td>
														<td align="left">
																<tt class="literal">net.sf.hibernate.cache.HashtableCacheProvider</tt>
														</td>
														<td align="left">memory</td>
														<td align="left"> </td>
														<td align="left">yes</td>
												</tr>
												<tr>
														<td align="left">EHCache</td>
														<td align="left">
																<tt class="literal">net.sf.hibernate.cache.EhCacheProvider</tt>
														</td>
														<td align="left">memory, disk</td>
														<td align="left"> </td>
														<td align="left">yes</td>
												</tr>
												<tr>
														<td align="left">OSCache</td>
														<td align="left">
																<tt class="literal">net.sf.hibernate.cache.OSCacheProvider</tt>
														</td>
														<td align="left">memory, disk</td>
														<td align="left"> </td>
														<td align="left">yes</td>
												</tr>
												<tr>
														<td align="left">SwarmCache</td>
														<td align="left">
																<tt class="literal">net.sf.hibernate.cache.SwarmCacheProvider</tt>
														</td>
														<td align="left">clustered (ip multicast)</td>
														<td align="left">yes (clustered invalidation)</td>
														<td align="left"> </td>
												</tr>
												<tr>
														<td align="left">JBoss TreeCache</td>
														<td align="left">
																<tt class="literal">net.sf.hibernate.cache.TreeCacheProvider</tt>
														</td>
														<td align="left">clustered (ip multicast), transactional</td>
														<td align="left">yes (replication)</td>
														<td align="left"> </td>
												</tr>
										</tbody>
								</table>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="performance-cache-mapping">
																</a>14.3.1. 对映射(Mapping)缓冲</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>类或者集合映射的<tt class="literal">&lt;cache&gt;</tt>元素可能有下列形式： </p>
								<div class="programlistingco">
										<pre class="programlisting">&lt;cache                                                      <span class="co">(1)</span>
                usage="transactional|read-write|nonstrict-read-write|read-only" /&gt;</pre>
										<div class="calloutlist">
												<table summary="Callout list" border="0">
														<tbody>
																<tr>
																		<td valign="top" align="left" width="5%">(1)</td>
																		<td valign="top" align="left">
																				<p>
																						<tt class="literal">usage</tt> 指定了缓存策略： <tt class="literal">transactional</tt>, <tt class="literal">read-write</tt>, <tt class="literal">nonstrict-read-write</tt> 或者 <tt class="literal">read-only</tt></p>
																		</td>
																</tr>
														</tbody>
												</table>
										</div>
								</div>
								<p>另外 (推荐首选?), 你可以在<tt class="literal">hibernate.cfg.xml</tt>中指定<tt class="literal">&lt;class-cache&gt;</tt> 和 <tt class="literal">&lt;collection-cache&gt;</tt> 元素。 </p>
								<p>
										<tt class="literal">usage</tt>属性指明了<span class="emphasis"><em>缓存并发策略（cache concurrency strategy）</em></span>。 </p>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="performance-cache-readonly">
																</a>14.3.2. 策略：只读缓存</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>如果你的应用程序需要读取一个持久化类的实例，但是并不打算修改它们，可以使用<tt class="literal">read-only</tt> 缓存。这是最简单，也是实用性最好的策略。甚至在集群中，它也能完美地运作。 </p>
								<pre class="programlisting">&lt;class name="eg.Immutable" mutable="false"&gt;
    &lt;cache usage="read-only"/&gt;
    ....
&lt;/class&gt;</pre>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="performance-cache-readwrite">
																</a>14.3.3. 策略:读/写缓存</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>如果应用程序需要更新数据，可能<tt class="literal">read-write</tt>缓存比较合适。如果需要可序列化事务隔离级别（serializable transaction isolation level），这种缓存决不能使用。如果在JTA环境中使用这种缓存，你必须指定<tt class="literal">hibernate.transaction.manager_lookup_class</tt>属性的值，给出得到JTA <tt class="literal">TransactionManager</tt>的策略。在其它环境中，你必须确保在<tt class="literal">Session.close()</tt>或者<tt class="literal">Session.disconnect()</tt>调用前，事务已经结束了。 如果你要在集群环境下使用这一策略，你必须确保底层的缓存实现支持锁定(locking)。内置的缓存提供器<span class="emphasis"><em>并不</em></span>支持。 </p>
								<pre class="programlisting">&lt;class name="eg.Cat" .... &gt;
    &lt;cache usage="read-write"/&gt;
    ....
    &lt;set name="kittens" ... &gt;
        &lt;cache usage="read-write"/&gt;
        ....
    &lt;/set&gt;
&lt;/class&gt;</pre>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="performance-cache-nonstrict">
																</a>14.3.4. 策略:不严格的读/写缓存</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>如果程序偶尔需要更新数据（也就是说，出现两个事务同时更新同一个条目的现象很不常见），也不需要十分严格的事务隔离，可能适用<tt class="literal">nonstrict-read-write</tt>缓存。如果在JTA环境中使用这种缓存，你必须指定<tt class="literal">hibernate.transaction.manager_lookup_class</tt>属性的值，给出得到JTA <tt class="literal">TransactionManager</tt>的策略。在其它环境中，你必须确保在<tt class="literal">Session.close()</tt>或者<tt class="literal">Session.disconnect()</tt>调用前，事务已经结束了。 </p>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="performance-cache-transactional">
																</a>14.3.5. 策略:事务缓存（transactional）</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>
										<tt class="literal">transactional</tt>缓存策略提供了对全事务缓存提供,比如JBoss TreeCache的支持。这样的缓存只能用于JTA环境，你必须指定<tt class="literal">hibernate.transaction.manager_lookup_class</tt>。 </p>
						</div>
						<p>没有一种缓存提供器能够支持所有的缓存并发策略。下面的表列出每种提供器与各种并发策略的兼容性。 </p>
						<div class="table">
								<a name="d0e8845">
								</a>
								<p class="title">
										<b>表 14.2. 缓存并发策略支持(Cache Concurrency Strategy Support)</b>
								</p>
								<table summary="缓存并发策略支持(Cache Concurrency Strategy Support)" border="1">
										<colgroup>
												<col align="left" />
												<col align="left" />
												<col align="left" />
												<col align="left" />
												<col align="left" />
										</colgroup>
										<thead>
												<tr>
														<th align="left">Cache</th>
														<th align="left">read-only</th>
														<th align="left">nonstrict-read-write</th>
														<th align="left">read-write</th>
														<th align="left">transactional</th>
												</tr>
										</thead>
										<tbody>
												<tr>
														<td align="left">Hashtable (not intended for production use)</td>
														<td align="left">yes</td>
														<td align="left">yes</td>
														<td align="left">yes</td>
														<td align="left"> </td>
												</tr>
												<tr>
														<td align="left">EHCache</td>
														<td align="left">yes</td>
														<td align="left">yes</td>
														<td align="left">yes</td>
														<td align="left"> </td>
												</tr>
												<tr>
														<td align="left">OSCache</td>
														<td align="left">yes</td>
														<td align="left">yes</td>
														<td align="left">yes</td>
														<td align="left"> </td>
												</tr>
												<tr>
														<td align="left">SwarmCache</td>
														<td align="left">yes</td>
														<td align="left">yes</td>
														<td align="left"> </td>
														<td align="left"> </td>
												</tr>
												<tr>
														<td align="left">JBoss TreeCache</td>
														<td align="left">yes</td>
														<td align="left"> </td>
														<td align="left"> </td>
														<td align="left">yes</td>
												</tr>
										</tbody>
								</table>
						</div>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="performance-sessioncache">
														</a>14.4. 管理Session缓存</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>不管何时你传递一个对象给<tt class="literal">save()</tt>, <tt class="literal">update()</tt>或者 <tt class="literal">saveOrUpdate()</tt> ,或者不管何时你使用<tt class="literal">load()</tt>, <tt class="literal">find()</tt>, <tt class="literal">iterate()</tt>或者<tt class="literal">filter()</tt>取得一个对象的时候,该对象被加入到<tt class="literal">Session</tt>的内部缓存中。当后继的<tt class="literal">flush()</tt>被调用时，对象的状态会和数据库进行同步。如果你在处理大量对象并且需要有效的管理内存的时候，你可能不希望发生这种同步，<tt class="literal">evict()</tt>方法可以从缓存中去掉对象和它的集合。 </p>
						<pre class="programlisting">Iterator cats = sess.iterate("from eg.Cat as cat"); //a huge result set
while ( cats.hasNext() ) {
    Cat cat = (Cat) iter.next();
    doSomethingWithACat(cat);
    sess.evict(cat);
}</pre>
						<p>Hibernate will evict associated entities automatically if the association is mapped with <tt class="literal">cascade="all"</tt> or <tt class="literal">cascade="all-delete-orphan"</tt>. 如果关联通过<tt class="literal">cascade="all"</tt> 或者 <tt class="literal">cascade="all-delete-orphan"</tt>实现，Hibernate会自动删除关联的实体。 </p>
						<p>
								<tt class="literal">Session</tt>也提供了一个<tt class="literal">contains()</tt>方法来判断是否一个实例处于这个session的缓存中。 </p>
						<p>要把所有的对象从session缓存中完全清除，请调用<tt class="literal">Session.clear()</tt>。 </p>
						<p>对于第二层缓存来说，在<tt class="literal">SessionFactory</tt>中定义了一些方法来从缓存中清除一个实例、整个类、集合实例或者整个集合。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="performance-querycache">
														</a>14.5. 查询缓存(Query Cache)</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>查询结果集也可以被缓存。只有当经常使用同样的参数进行查询时，这才会有些用处。要使用查询缓存，首先你要打开它，设置<tt class="literal">hibernate.cache.use_query_cache=true</tt>这个属性。这样会创建两个缓存区域——一个保存查询结果集(<tt class="literal">net.sf.hibernate.cache.QueryCache</tt>),另一个保存最近查询的表的时间戳(<tt class="literal">net.sf.hibernate.cache.UpdateTimestampsCache</tt>)。请注意查询缓存并不缓存结果集中包含实体的状态；它只缓存标识符属性的值和值类型的结果。所以查询缓存通常会和第二层缓存一起使用。 </p>
						<p>大多数查询并不会从缓存中获得什么好处，所以默认查询是不进行缓存的。要进行缓存，调用 <tt class="literal">Query.setCacheable(true)</tt>。这个调用会让查询在执行时去从缓存中查找结果，或者把结果集放到缓存去。 </p>
						<p>如果你要对查询缓存的失效政策进行精确的控制，你必须调用<tt class="literal">Query.setCacheRegion()</tt>来为每个查询指定一个命名的缓存区域。 </p>
						<pre class="programlisting">List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
    .setEntity("blogger", blogger)
    .setMaxResults(15)
    .setCacheable(true)
    .setCacheRegion("frontpages")
    .list();</pre>
				</div>
		</div>
		<div class="navfooter">
				<hr />
				<table width="100%" summary="Navigation footer">
						<tbody>
								<tr>
										<td align="left" width="40%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/querysql.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<td align="middle" width="20%">
												<a accesskey="u" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">上一级</font>
												</a>
										</td>
										<td align="right" width="40%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/toolsetguide.html"><font color="#002c99">下一页</font></a></td>
								</tr>
								<tr>
										<td valign="top" align="left" width="40%">第 13 章 原生SQL查询 </td>
										<td align="middle" width="20%">
												<a accesskey="h" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">起始页</font>
												</a>
										</td>
										<td valign="top" align="right" width="40%"> 第 15 章 工具箱指南</td>
								</tr>
						</tbody>
				</table>
		</div>
<img src ="http://www.cnitblog.com/forrest/aggbug/16233.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2006-08-31 18:41 <a href="http://www.cnitblog.com/forrest/articles/16233.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第 12 章 条件查询(Criteria Query)</title><link>http://www.cnitblog.com/forrest/articles/16232.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Thu, 31 Aug 2006 10:40:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/articles/16232.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/16232.html</wfw:comment><comments>http://www.cnitblog.com/forrest/articles/16232.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/16232.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/16232.html</trackback:ping><description><![CDATA[
		<div class="navheader">
				<table width="100%" summary="Navigation header">
						<tbody>
								<tr>
										<th align="middle" colspan="3">第 12 章 条件查询(Criteria Query)</th>
								</tr>
								<tr>
										<td align="left" width="20%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/queryhql.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<th align="middle" width="60%"> </th>
										<td align="right" width="20%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/querysql.html"><font color="#002c99">下一页</font></a></td>
								</tr>
						</tbody>
				</table>
				<font color="#002c99">
						<hr />
				</font>
		</div>
		<div class="chapter" lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h2 class="title">
												<a name="querycriteria">
												</a>第 12 章 条件查询(Criteria Query)</h2>
								</div>
						</div>
						<div>
						</div>
				</div>
				<p>现在Hibernate也支持一种直观的、可扩展的条件查询API。目前为止，这个API还没有更成熟的HQL查询那么强大，也没有那么多查询能力。特别要指出，条件查询也不支持投影（projection）或统计函数（aggregation）。 </p>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="querycriteria-creating">
														</a>12.1. 创建一个<tt class="literal">Criteria</tt>实例</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>
								<tt class="literal">net.sf.hibernate.Criteria</tt>这个接口代表对一个特定的持久化类的查询。<tt class="literal">Session</tt>是用来制造<tt class="literal">Criteria</tt>实例的工厂。 </p>
						<pre class="programlisting">Criteria crit = sess.createCriteria(Cat.class);
crit.setMaxResults(50);
List cats = crit.list();</pre>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="querycriteria-narrowing">
														</a>12.2. 缩小结果集范围</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>一个查询条件(Criterion)是<tt class="literal">net.sf.hibernate.expression.Criterion</tt>接口的一个实例。类<tt class="literal">net.sf.hibernate.expression.Expression</tt>定义了获得一些内置的<tt class="literal">Criterion</tt>类型。 </p>
						<pre class="programlisting">List cats = sess.createCriteria(Cat.class)
    .add( Expression.like("name", "Fritz%") )
    .add( Expression.between("weight", minWeight, maxWeight) )
    .list();</pre>
						<p>表达式（Expressions）可以按照逻辑分组. </p>
						<pre class="programlisting">List cats = sess.createCriteria(Cat.class)
    .add( Expression.like("name", "Fritz%") )
    .add( Expression.or(
    	Expression.eq( "age", new Integer(0) ),
    	Expression.isNull("age")
    ) )
    .list();</pre>
						<pre class="programlisting">List cats = sess.createCriteria(Cat.class)
    .add( Expression.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) )
    .add( Expression.disjunction()
        .add( Expression.isNull("age") )
    	.add( Expression.eq("age", new Integer(0) ) )
    	.add( Expression.eq("age", new Integer(1) ) )
    	.add( Expression.eq("age", new Integer(2) ) )
    ) )
    .list();</pre>
						<p>有很多预制的条件类型（<tt class="literal">Expression</tt>的子类）。有一个特别有用，可以让你直接嵌入SQL。 </p>
						<pre class="programlisting">List cats = sess.createCriteria(Cat.class)
    .add( Expression.sql("lower($alias.name) like lower(?)", "Fritz%", Hibernate.STRING) )
    .list();</pre>
						<p>其中的<tt class="literal">{alias}</tt>是一个占位符，它将会被所查询实体的行别名所替代。(原文:The <tt class="literal">{alias}</tt> placeholder with be replaced by the row alias of the queried entity.) </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="querycriteria-ordering">
														</a>12.3. 对结果排序</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>可以使用<tt class="literal">net.sf.hibernate.expression.Order</tt>对结果集排序. </p>
						<pre class="programlisting">List cats = sess.createCriteria(Cat.class)
    .add( Expression.like("name", "F%")
    .addOrder( Order.asc("name") )
    .addOrder( Order.desc("age") )
    .setMaxResults(50)
    .list();</pre>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="querycriteria-associations">
														</a>12.4. 关联（Associations）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>你可以在关联之间使用<tt class="literal">createCriteria()</tt>，很容易地在存在关系的实体之间指定约束。 </p>
						<pre class="programlisting">List cats = sess.createCriteria(Cat.class)
    .add( Expression.like("name", "F%")
    .createCriteria("kittens")
        .add( Expression.like("name", "F%")
    .list();</pre>
						<p>注意，第二个<tt class="literal">createCriteria()</tt>返回一个<tt class="literal">Criteria</tt>的新实例，指向<tt class="literal">kittens</tt>集合类的元素。 </p>
						<p>下面的替代形式在特定情况下有用。 </p>
						<pre class="programlisting">List cats = sess.createCriteria(Cat.class)
    .createAlias("kittens", "kt")
    .createAlias("mate", "mt")
    .add( Expression.eqProperty("kt.name", "mt.name") )
    .list();</pre>
						<p>（<tt class="literal">createAlias()</tt>）并不会创建一个<tt class="literal">Criteria</tt>的新实例。） </p>
						<p>请注意，前面两个查询中<tt class="literal">Cat</tt>实例所持有的kittens集合类<span class="emphasis"><em>并没有</em></span>通过criteria预先过滤！如果你希望只返回满足条件的kittens,你必须使用<tt class="literal">returnMaps()</tt>。 </p>
						<pre class="programlisting">List cats = sess.createCriteria(Cat.class)
    .createCriteria("kittens", "kt")
        .add( Expression.eq("name", "F%") )
    .returnMaps()
    .list();
Iterator iter = cats.iterator();
while ( iter.hasNext() ) {
    Map map = (Map) iter.next();
    Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS);
    Cat kitten = (Cat) map.get("kt");
}</pre>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="querycriteria-dynamicfetching">
														</a>12.5. 动态关联对象获取（Dynamic association fetching）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>可以在运行时通过<tt class="literal">setFetchMode()</tt>来改变关联对象自动获取的策略。 </p>
						<pre class="programlisting">List cats = sess.createCriteria(Cat.class)
    .add( Expression.like("name", "Fritz%") )
    .setFetchMode("mate", FetchMode.EAGER)
    .setFetchMode("kittens", FetchMode.EAGER)
    .list();</pre>
						<p>这个查询会通过外连接(outer join)同时获得 <tt class="literal">mate</tt>和<tt class="literal">kittens</tt>。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="querycriteria-examples">
														</a>12.6. 根据示例查询（Example queries）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>
								<tt class="literal">net.sf.hibernate.expression.Example</tt>类允许你从指定的实例创造查询条件。 </p>
						<pre class="programlisting">Cat cat = new Cat();
cat.setSex('F');
cat.setColor(Color.BLACK);
List results = session.createCriteria(Cat.class)
    .add( Example.create(cat) )
    .list();</pre>
						<p>版本属性，表示符属性和关联都会被忽略。默认情况下，null值的属性也被排除在外。 </p>
						<p>You can adjust how the <tt class="literal">Example</tt> is applied. 你可以调整<tt class="literal">示例(Example)</tt>如何应用。 </p>
						<pre class="programlisting">Example example = Example.create(cat)
    .excludeZeroes()           //exclude zero valued properties
    .excludeProperty("color")  //exclude the property named "color"
    .ignoreCase()              //perform case insensitive string comparisons
    .enableLike();             //use like for string comparisons
List results = session.createCriteria(Cat.class)
    .add(example)
    .list();</pre>
						<p>你甚至可以用示例对关联对象建立criteria。 </p>
						<pre class="programlisting">List results = session.createCriteria(Cat.class)
    .add( Example.create(cat) )
    .createCriteria("mate")
        .add( Example.create( cat.getMate() ) )
    .list();</pre>
				</div>
		</div>
		<div class="navfooter">
				<hr />
				<table width="100%" summary="Navigation footer">
						<tbody>
								<tr>
										<td align="left" width="40%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/queryhql.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<td align="middle" width="20%">
												<a accesskey="u" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">上一级</font>
												</a>
										</td>
										<td align="right" width="40%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/querysql.html"><font color="#002c99">下一页</font></a></td>
								</tr>
								<tr>
										<td valign="top" align="left" width="40%">第 11 章 Hibernate查询语言(Query Language), 即HQL </td>
										<td align="middle" width="20%">
												<a accesskey="h" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">起始页</font>
												</a>
										</td>
										<td valign="top" align="right" width="40%"> 第 13 章 原生SQL查询</td>
								</tr>
						</tbody>
				</table>
		</div>
<img src ="http://www.cnitblog.com/forrest/aggbug/16232.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2006-08-31 18:40 <a href="http://www.cnitblog.com/forrest/articles/16232.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第 10 章 事务和并行（Transactions And Concurrency） 第 11 章 Hibernate查询语言(Query Language), 即HQL</title><link>http://www.cnitblog.com/forrest/articles/16231.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Thu, 31 Aug 2006 10:39:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/articles/16231.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/16231.html</wfw:comment><comments>http://www.cnitblog.com/forrest/articles/16231.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/16231.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/16231.html</trackback:ping><description><![CDATA[
		<div class="navheader">
				<table width="100%" summary="Navigation header">
						<tbody>
								<tr>
										<th align="middle" colspan="3">第 10 章 事务和并行（Transactions And Concurrency）</th>
								</tr>
								<tr>
										<td align="left" width="20%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/manipulatingdata.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<th align="middle" width="60%"> </th>
										<td align="right" width="20%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/queryhql.html"><font color="#002c99">下一页</font></a></td>
								</tr>
						</tbody>
				</table>
				<font color="#002c99">
						<hr />
				</font>
		</div>
		<div class="chapter" lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h2 class="title">
												<a name="transactions">
												</a>第 10 章 事务和并行（Transactions And Concurrency）</h2>
								</div>
						</div>
						<div>
						</div>
				</div>
				<p>Hibernate本身并不是数据库，它只是一个轻量级的对象－关系数据库映射（object-relational）工具。它的事务交由底层的数据库连接管理，如果数据库连接有JTA的支持，那么在<tt class="literal">Session</tt>中进行的操作将是整个原子性JTA事务的一部分。Hibernate可以看作是添加了面向对象语义的JDBC瘦适配器（thin adapter）。 </p>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="ttransactions-basics">
														</a>10.1. 配置，会话和工厂（Configurations, Sessions and Factories）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>
								<tt class="literal">SessionFactory</tt>的创建需要耗费大量资源，它是线程安全（threadsafe）的对象，在应用中它被所有线程共享。而<tt class="literal">Session</tt>的创建耗费资源很少，它不是线程安全的对象，对于一个简单商业过程（business process），它应该只被使用一次，然后被丢弃。举例来说，当Hibernate在基于servlet的应用中，servlet能够以下面的方式得到<tt class="literal">SessionFactory</tt>。 </p>
						<pre class="programlisting">SessionFactory sf = (SessionFactory)getServletContext().getAttribute("my.session.factory");</pre>
						<p>每次调用SessionFactory的service方法能够生成一个新的<tt class="literal">Session</tt>对象，然后调用Session的<tt class="literal">flush()</tt>，调用<tt class="literal">commit()</tt>提交它的连接，调用<tt class="literal">close()</tt>关闭它，最终丢弃它。(<tt class="literal">SessionFactory</tt>可能被保存在JNDI或者一个静态的<span class="emphasis"><em>单例（Singleton）</em></span>辅助变量中。） </p>
						<p>在无状态的session bean中，可以同样使用类似的方法。bean在<tt class="literal">setSessionContext()</tt>中得到<tt class="literal">SessionFactory</tt>的实例，每个商业方法会生成一个<tt class="literal">Session</tt>对象，调用它的<tt class="literal">flush()</tt>和<tt class="literal">close()</tt>，当然，应用不应该<tt class="literal">commit()</tt>connection. (把它留给JTA.在容器管理的事务中，数据库连接会自动完成事务。) </p>
						<p>我们用上述方法使用Hibernate 的<tt class="literal">Transaction</tt> API，对<tt class="literal">Transaction</tt>执行一次<tt class="literal">commit()</tt>会把所有状态同步，把底层的数据库连接提交(对JTA 事务会特殊处理。) </p>
						<p>这里需要理解<tt class="literal">flush()</tt>的含义。 <tt class="literal">flush()</tt>将持久化存储与内存中的变化进行同步，但<span class="emphasis"><em>不是</em></span>将内存的变化与持久化存储进行同步。注意对所有的Hibernate JDBD 连接/事务来说，其隔离级别将施加于所有的Hibernate执行的操作之上！ </p>
						<p>接下来的几小节将讨论利用版本化的方法来确保事务原子性，这些“高级”方法需要小心使用。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="transactions-threads">
														</a>10.2. 线程和连接（Threads and connections）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>在创建Hibernate会话（Session）时，你应该留意以下的实践（practices）： </p>
						<div class="itemizedlist">
								<ul type="disc" compact="">
										<li>
												<p>对于一个数据库连接，不要创建一个以上的<tt class="literal">Session</tt>或<tt class="literal">Transaction</tt>。 </p>
										</li>
										<li>
												<p>在对于一个数据库连接、一个事务使用多个<tt class="literal">Session</tt>时，你尤其需要格外地小心。<tt class="literal">Session</tt>对象会记录下调入数据更新的情况，所以另一个<tt class="literal">Session</tt>对象可能会遇到过时的数据。 </p>
										</li>
										<li>
												<p>
														<tt class="literal">Session</tt>
														<span class="emphasis">
																<em>不是</em>
														</span>线程安全的。决不要在两个并发的线程中访问同一个<tt class="literal">Session</tt>。一个<tt class="literal">Session</tt>一般只对应一批需要一次性完成的单元操作！ </p>
										</li>
								</ul>
						</div>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="transactions-identity">
														</a>10.3. 考虑对象辨别</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>程序可能在两批单元操作中并发访问同一个对象的持久化状态。不管怎样，持久化类的一个实例不可能在两个<tt class="literal">Session</tt>中共享。所以有两种不同的辨别方式： </p>
						<div class="variablelist">
								<dl>
										<dt>
												<span class="term">数据库辨别</span>
										</dt>
										<dd>
												<p>
														<tt class="literal">foo.getId().equals( bar.getId() )</tt>
												</p>
										</dd>
										<dt>
												<span class="term">JVM 辨别</span>
										</dt>
										<dd>
												<p>
														<tt class="literal">foo==bar</tt>
												</p>
										</dd>
								</dl>
						</div>
						<p>对于依附于某个<span class="emphasis"><em>特定</em></span><tt class="literal">Session</tt>的对象，两种辨别方式是等价的。然而，当程序可能在两个不同的session中并发访问“同一个”（持久化辨别）商业对象时，两个实例（对于JVM辨别来说）却可能是“不同”的。 </p>
						<p>这种方式把关于并发的头疼问题留给了Hibernate和数据库。程序不需要对任何商业对象进行同步，只要程序坚持每个<tt class="literal">Session</tt>一个线程，或者对象辨别的策略（在一个<tt class="literal">Session</tt>重，程序可以安全的使用<tt class="literal">==</tt>来比较对象）。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="transactions-optimistic">
														</a>10.4. 乐观并发控制（Optimistic concurrency control）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>许多商业过程需要一系列与用户进行交互的过程，数据库访问穿插在这些过程中。对于web和企业应用来说，跨一个用户交互过程的数据事务是不可接受的。 </p>
						<p>维护各商业事务间的隔离（isolocation）就成为应用层的部分责任，我们把这种过程称为长时间运行的<span class="emphasis"><em>应用事务（application transaction）</em></span>。单一的应用事务可能跨越多个数据库事务。如果这些数据库事务中只有一个（最后一个）保存了被修改的数据，其他事务只是简单地读数据，则这个应用事务就是原子性的。 </p>
						<p>唯一满足高并发性以及高可扩展性的方法是使用带有版本化的乐观并发控制。Hibernate为使用乐观并发控制的代码提供了三种可能的方法。 </p>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="transactions-optimistic-longsession">
																</a>10.4.1. 使用长生命周期带有自动版本化的会话</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>在整个商业过程中使用一个单独的<tt class="literal">Session</tt>实例以及它的持久化实例，这个<tt class="literal">Session</tt>使用带有版本化的乐观锁定机制，来确保多个数据库事务对于应用来说只是一个逻辑上的事务。在等待用户交互时，<tt class="literal">Session</tt>断开与数据库的连接。这个方法从数据库访问方面来看是最有效的，应用不需要关心对自己的版本检查或是重新与不需要序列化（transient）的实例进行关联。 </p>
								<p>在整个应用事务中，使用单一的<tt class="literal">Session</tt> 实例和它的持久化实例。 </p>
								<p>
										<tt class="literal">Session</tt> 使用带有版本化的乐观锁定来保证多个数据库事务对程序来说就如同是单一的逻辑应用事务。在等待用户交互的时候，<tt class="literal">Session</tt> 脱离所有的底层JDBC连接。对于数据库访问来说，这种方法是最高效的。程序自己不需要关心版本检查或者把已经脱离session的实例重新关联到session。 </p>
								<pre class="programlisting">// foo is an instance loaded earlier by the Session
session.reconnect();
foo.setProperty("bar");
session.flush();
session.connection().commit();
session.disconnect();</pre>
								<p>
										<tt class="literal">foo</tt>对象仍然知道是哪个<tt class="literal">Session</tt>把自己装载的。 只要<tt class="literal">Session</tt> 拥有一个JDBC连接，我们可以把对象的更改提交。 </p>
								<p>如果我们的 <tt class="literal">Session</tt> 太大，以至于在用户思考的时间内无法保存住，这种模式就会出现问题。比如，<tt class="literal">HttpSession</tt>应该保持尽量小。因为<tt class="literal">Session</tt>也持有（必须的）第一级缓存，包含所有被装载的对象，我们只能在很少的request/response周期中使用这一策略。这种少用是被鼓励的，因为<tt class="literal">Session</tt> 很快就会出现过时的数据。 </p>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="transactions-optimistic-detached">
																</a>10.4.2. 使用带有自动版本化的多个会话</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>每个与持久化存储的交互出现在一个新的<tt class="literal">Session</tt>中，在每次与数据库的交互中，使用相同的持久化实例。应用操作那些从其它<tt class="literal">Session</tt>调入的已经脱离session的实例的状态，通过使用<tt class="literal">Session.update()</tt>或者<tt class="literal">Session.saveOrUpdate()</tt>来重新建立与它们的关联。 </p>
								<pre class="programlisting">// foo is an instance loaded by a previous Session
foo.setProperty("bar");
session = factory.openSession();
session.saveOrUpdate(foo);
session.flush();
session.connection().commit();
session.close();</pre>
								<p>你也可以调用<tt class="literal">lock()</tt>而非<tt class="literal">update()</tt>，如果你确信对象没有被修改过，可以使用<tt class="literal">LockMode.READ</tt>（进行一次版本检查，而跳过所有的缓存）。 </p>
						</div>
						<div class="sect2" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h3 class="title">
																<a name="transactions-optimistic-manual">
																</a>10.4.3. 应用程序自己进行版本检查</h3>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>每当一个新的<tt class="literal">Session</tt>中与数据库出现交互的时候，这个session会在操作持久化实例前重新把它们从数据库中装载进来。我们现在所说的方式就是你的应用程序自己使用版本检查来确保应用事务的隔离性。（当然，Hibernate仍会为你<span class="emphasis"><em>更新</em></span>版本号）。从数据库访问方面来看，这种方法是最没有效率的，与entity EJB方式类似。 </p>
								<pre class="programlisting">// foo is an instance loaded by a previous Session
session = factory.openSession();
int oldVersion = foo.getVersion();
session.load( foo, foo.getKey() );
if ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException();
foo.setProperty("bar");
session.flush();
session.connection().commit();
session.close();</pre>
								<p>当然，如果在低数据并行（low-data-concurrency）的环境中，并不需要版本检查，你仍可以使用这个方法，只需要忽略版本检查。 </p>
						</div>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="transactions-disconnection">
														</a>10.5. 会话断开连接（Session disconnection）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>The first approach described above is to maintain a single <tt class="literal">Session</tt> for a whole business process thats spans user think time. (For example, a servlet might keep a <tt class="literal">Session</tt> in the user's <tt class="literal">HttpSession</tt>.) For performance reasons you should </p>
						<p>上面提到的第一种方法是对于对一个用户的一次登录产生的整个商业过程维护一个<tt class="literal">Session</tt>。（举例来说，servlet有可能会在用户的<tt class="literal">HttpSession</tt>中保留一个<tt class="literal">Session</tt>）。为性能考虑，你必须 </p>
						<div class="orderedlist">
								<ol type="1" compact="">
										<li>
												<p>提交<tt class="literal">Transaction</tt>（或者JDBC连接），然后 </p>
										</li>
										<li>
												<p>(在等待用户操作前，)断开<tt class="literal">Session</tt>与JDBC连接。 </p>
										</li>
								</ol>
						</div>
						<p>
								<tt class="literal">Session.disconnect()</tt>方法会断开会话与JDBC的连接，把连接返还给连接池（除非是你自己提供这个连接的）。 </p>
						<p>
								<tt class="literal">Session.reconnect()</tt>方法会得到一个新的连接（你也可以自己提供一个），重新开始会话。在重新连接后，你可以通过对任何可能被其它事务更新的对象调用<tt class="literal">Session.lock()</tt>方法，来强迫对你没有更新的数据进行版本检查。你不需要对<span class="emphasis"><em>正在</em></span>更新的数据调用lock()。 </p>
						<p>这是一个例子： </p>
						<pre class="programlisting">SessionFactory sessions;
List fooList;
Bar bar;
....
Session s = sessions.openSession();

Transaction tx = null;
try {
    tx = s.beginTransaction();

    fooList = s.find(
    	"select foo from eg.Foo foo where foo.Date = current date"
        // uses db2 date function
    );
    bar = (Bar) s.create(Bar.class);

    tx.commit();
}
catch (Exception e) {
    if (tx!=null) tx.rollback();
    s.close();
    throw e;
}
s.disconnect();</pre>
						<p>接下来： </p>
						<pre class="programlisting">s.reconnect();

try {
    tx = s.beginTransaction();

    bar.setFooTable( new HashMap() );
    Iterator iter = fooList.iterator();
    while ( iter.hasNext() ) {
        Foo foo = (Foo) iter.next();
        s.lock(foo, LockMode.READ);    //check that foo isn't stale
        bar.getFooTable().put( foo.getName(), foo );
    }

    tx.commit();
}
catch (Exception e) {
    if (tx!=null) tx.rollback();
    throw e;
}
finally {
    s.close();
}</pre>
						<p>从上面的例子可以看到<tt class="literal">Transaction</tt>和<tt class="literal">Session</tt>之间是多对一的关系。一个<tt class="literal">Session</tt>表示了应用程序与数据库之间的一个对话，<tt class="literal">Transaction</tt>把这个对话分隔成一个个在数据库级别具有原子性的单元。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="transactions-locking">
														</a>10.6. 悲观锁定（Pessimistic Locking）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>用户不需要在锁定策略上花费过多时间，通常我们可以对JDBC连接选定一种隔离级别（isolationn level），然后让数据库完成所有的工作。高级用户可能希望得到悲观锁定或者在新的事务开始时重新得到锁。 </p>
						<p>Hibernate一直都会使用数据库的锁定机制,而不会在内存中锁定对象。 </p>
						<p>
								<tt class="literal">LockMode</tt>类定义了Hibernate需要的不同的锁级别。锁由以下的机制得到： </p>
						<div class="itemizedlist">
								<ul type="disc" compact="">
										<li>
												<p>
														<tt class="literal">LockMode.WRITE</tt>在Hibernate更新或插入一行数据时自动得到。 </p>
										</li>
										<li>
												<p>
														<tt class="literal">LockMode.UPGRADE</tt>在用户通过<tt class="literal">SELECT ... FOR UPDATE</tt>这样的特定请求得到，需要数据库支持这种语法。 </p>
										</li>
										<li>
												<p>
														<tt class="literal">LockMode.UPGRADE_NOWAIT</tt>在用户通过<tt class="literal">SELECT ... FOR UPDATE NOWAIT</tt>这样的特定请求在Oracle数据库环境下得到。 </p>
										</li>
										<li>
												<p>
														<tt class="literal">LockMode.READ</tt>在Hibernate在不断读（Repeatable Read）和序列化（Serializable）的隔离级别下读取数据时得到。也可以通过用户的明确请求重新获得。 </p>
										</li>
										<li>
												<p>
														<tt class="literal">LockMode.NONE</tt>表示没有锁。所有对象在<tt class="literal">Transaction</tt>结束时会切换到这种锁模式，通过调用<tt class="literal">update()</tt>或者<tt class="literal">saveOrUpdate()</tt>与会话进行关联的对象,开始时也会在这种锁模式。 </p>
										</li>
								</ul>
						</div>
						<p>“明确的用户请求”会以下的几种方式出现： </p>
						<div class="itemizedlist">
								<ul type="disc" compact="">
										<li>
												<p>调用<tt class="literal">Session.load()</tt>，指定一种<tt class="literal">LockMode</tt>。 </p>
										</li>
										<li>
												<p>调用<tt class="literal">Session.lock()</tt>。 </p>
										</li>
										<li>
												<p>调用<tt class="literal">Query.setLockMode()</tt>。 </p>
										</li>
								</ul>
						</div>
						<p>如果在调用<tt class="literal">Session.load()</tt>时指定了<tt class="literal">UPGRADE</tt>或者<tt class="literal">UPGRADE_NOWAIT</tt>，并且请求的对象还没有被会话调入，那么这个对象会以<tt class="literal">SELECT ... FOR UPDATE</tt>的方式调入。如果调用<tt class="literal">load()</tt>在一个已经调入的对象，并且这个对象调入时的锁级别没有请求时来得严格，Hibernate会对这个对象调用<tt class="literal">lock()</tt>。 </p>
						<p>
								<tt class="literal">Session.lock()</tt>会执行版本号检查的特定的锁模式是：<tt class="literal">READ</tt>，<tt class="literal">UPGRADE</tt>或者<tt class="literal">UPGRADE_NOWAIT</tt>。（在<tt class="literal">UPGRADE</tt>或者<tt class="literal">UPGRADE_NOWAIT</tt>，<tt class="literal">SELECT ... FOR UPGRADE</tt>使用的情况下。） </p>
						<p>如果数据库不支持所请求的锁模式，Hibernate将会选择一种合适的受支持的锁模式替换（而不是抛出一个异常）。这确保了应用具有可移植性<br /></p>
						<div class="navheader">
								<table width="100%" summary="Navigation header">
										<tbody>
												<tr>
														<th align="middle" colspan="3">第 11 章 Hibernate查询语言(Query Language), 即HQL</th>
												</tr>
												<tr>
														<td align="left" width="20%">
																<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/transactions.html">
																		<font color="#002c99">上一页</font>
																</a> </td>
														<th align="middle" width="60%"> </th>
														<td align="right" width="20%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/querycriteria.html"><font color="#002c99">下一页</font></a></td>
												</tr>
										</tbody>
								</table>
								<font color="#002c99">
										<hr />
								</font>
						</div>
						<div class="chapter" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h2 class="title">
																<a name="queryhql">
																</a>第 11 章 Hibernate查询语言(Query Language), 即HQL</h2>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>Hibernate装备了一种极为有力的查询语言，（有意地）看上去很像SQL。但是别被语法蒙蔽，HQL是完全面向对象的，具备继承、多态和关联等特性。 </p>
								<div class="sect1" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h2 class="title" style="CLEAR: both">
																		<a name="queryhql-casesensitivity">
																		</a>11.1. 大小写敏感性(Case Sensitivity)</h2>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>除了Java类和属性名称外，查询都是大小写不敏感的。 所以， <tt class="literal">SeLeCT</tt> 和 <tt class="literal">sELEct</tt> 以及 <tt class="literal">SELECT</tt> 相同的，但是 <tt class="literal">net.sf.hibernate.eg.FOO</tt> 和 <tt class="literal">net.sf.hibernate.eg.Foo</tt> 是不同的， <tt class="literal">foo.barSet</tt> 和 <tt class="literal">foo.BARSET</tt>也是不同的。 </p>
										<p>本手册使用小写的HQL关键词。有些用户认为在查询中使用大写的关键字更加易读，但是我们认为嵌入在Java代码中这样很难看。 </p>
								</div>
								<div class="sect1" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h2 class="title" style="CLEAR: both">
																		<a name="queryhql-from">
																		</a>11.2. from 子句</h2>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>可能最简单的Hibernate查询是这样的形式： </p>
										<pre class="programlisting">from eg.Cat</pre>
										<p>它简单的返回所有<tt class="literal">eg.Cat</tt>类的实例。 </p>
										<p>大部分情况下，你需要赋予它一个<span class="emphasis"><em>别名（alias）</em></span>，因为你在查询的其他地方也会引用这个<tt class="literal">Cat</tt>。 </p>
										<pre class="programlisting">from eg.Cat as cat</pre>
										<p>上面的语句为<tt class="literal">Cat</tt>赋予了一个别名<tt class="literal">cat</tt> 。所以后面的查询可以用这个简单的别名了。<tt class="literal">as</tt>关键字是可以省略的，我们也可以写成这样： </p>
										<pre class="programlisting">from eg.Cat cat</pre>
										<p>可以出现多个类，结果是它们的笛卡尔积，或者称为“交叉”连接。 </p>
										<pre class="programlisting">from Formula, Parameter</pre>
										<pre class="programlisting">from Formula as form, Parameter as param</pre>
										<p>让查询中的别名服从首字母小写的规则，我们认为这是一个好习惯。这和Java对局部变量的命名规范是一致的。(比如，<tt class="literal">domesticCat</tt>). </p>
								</div>
								<div class="sect1" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h2 class="title" style="CLEAR: both">
																		<a name="queryhql-joins">
																		</a>11.3. 联合（Associations）和连接（joins）</h2>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>你可以使用<tt class="literal">join</tt>定义两个实体的连接，同时指明别名。 </p>
										<pre class="programlisting">from eg.Cat as cat 
    inner join cat.mate as mate
    left outer join cat.kittens as kitten

from eg.Cat as cat left join cat.mate.kittens as kittens

from Formula form full join form.parameter param</pre>
										<p>支持的连接类型是从ANSI SQL借用的： </p>
										<div class="itemizedlist">
												<ul type="disc" compact="">
														<li>
																<p>
																		<tt class="literal">内连接，inner join</tt>
																</p>
														</li>
														<li>
																<p>
																		<tt class="literal">左外连接，left outer join</tt>
																</p>
														</li>
														<li>
																<p>
																		<tt class="literal">右外连接，right outer join</tt>
																</p>
														</li>
														<li>
																<p>
																		<tt class="literal">全连接，full join</tt> (不常使用) </p>
														</li>
												</ul>
										</div>
										<p>
												<tt class="literal">inner join</tt>, <tt class="literal">left outer join</tt> 和 <tt class="literal">right outer join</tt> 都可以简写。 </p>
										<pre class="programlisting">from eg.Cat as cat 
    join cat.mate as mate
    left join cat.kittens as kitten</pre>
										<p>并且，加上 "fetch"后缀的抓取连接可以让联合的对象随着它们的父对象的初始化而初始化，只需要一个select语句。这在初始化一个集合的时候特别有用。它有效地覆盖了映射文件中对关联和集合的外连接定义。 </p>
										<pre class="programlisting">from eg.Cat as cat 
    inner join fetch cat.mate
    left join fetch cat.kittens</pre>
										<p>抓取连接一般不需要赋予别名，因为被联合的对象应该不会在<tt class="literal">where</tt>子句（或者任何其它子句）中出现。并且，被联合的对象也不会在查询结果中直接出现。它们是通过父对象进行访问的。 </p>
										<p>请注意，目前的实现中，在一次查询中只会抓取一个集合（其他的一切都做不到。）（？原文为：only one collection role may be fetched in a query）。也请注意，在使用<tt class="literal">scroll()</tt>或者 <tt class="literal">iterate()</tt>方式调用的查询中，是禁止使用<tt class="literal">fetch</tt>构造的。最后，请注意<tt class="literal">full join fetch</tt>和<tt class="literal">right join fetch</tt>是没有意义的。 </p>
								</div>
								<div class="sect1" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h2 class="title" style="CLEAR: both">
																		<a name="queryhql-select">
																		</a>11.4. select子句</h2>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>
												<tt class="literal">select</tt>子句选择在结果集中返回哪些对象和属性。思考一下下面的例子： </p>
										<pre class="programlisting">select mate 
from eg.Cat as cat 
    inner join cat.mate as mate</pre>
										<p>这个查询会选择出作为其它猫（<tt class="literal">Cat</tt>）朋友（<tt class="literal">mate</tt>）的那些猫。当然，你可以更加直接的写成下面的形式： </p>
										<pre class="programlisting">select cat.mate from eg.Cat cat</pre>
										<p>你甚至可以选择集合元素，使用特殊的<tt class="literal">elements</tt>功能。下面的查询返回所有猫的小猫。 </p>
										<pre class="programlisting">select elements(cat.kittens) from eg.Cat cat</pre>
										<p>查询可以返回任何值类型的属性，包括组件类型的属性： </p>
										<pre class="programlisting">select cat.name from eg.DomesticCat cat
where cat.name like 'fri%'

select cust.name.firstName from Customer as cust</pre>
										<p>查询可以用元素类型是<tt class="literal">Object[]</tt>的一个数组返回多个对象和/或多个属性。 </p>
										<pre class="programlisting">select mother, offspr, mate.name 
from eg.DomesticCat as mother
    inner join mother.mate as mate
    left outer join mother.kittens as offspr</pre>
										<p>或者实际上是类型安全的Java对象 </p>
										<pre class="programlisting">select new Family(mother, mate, offspr)
from eg.DomesticCat as mother
    join mother.mate as mate
    left join mother.kittens as offspr</pre>
										<p>上面的代码假定<tt class="literal">Family</tt>有一个合适的构造函数。 </p>
								</div>
								<div class="sect1" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h2 class="title" style="CLEAR: both">
																		<a name="queryhql-aggregation">
																		</a>11.5. 统计函数(Aggregate functions)</h2>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>HQL查询可以返回属性的统计函数的结果。 </p>
										<pre class="programlisting">select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat)
from eg.Cat cat</pre>
										<p>在<tt class="literal">select</tt>子句中，统计函数的变量也可以是集合。 </p>
										<pre class="programlisting">select cat, count( elements(cat.kittens) ) 
from eg.Cat cat group by cat</pre>
										<p>下面是支持的统计函数列表： </p>
										<div class="itemizedlist">
												<ul type="disc" compact="">
														<li>
																<p>
																		<tt class="literal">avg(...), sum(...), min(...), max(...)</tt>
																</p>
														</li>
														<li>
																<p>
																		<tt class="literal">count(*)</tt>
																</p>
														</li>
														<li>
																<p>
																		<tt class="literal">count(...), count(distinct ...), count(all...)</tt>
																</p>
														</li>
												</ul>
										</div>
										<p>
												<tt class="literal">distinct</tt> 和 <tt class="literal">all</tt>关键字的用法和语义与SQL相同。 </p>
										<pre class="programlisting">select distinct cat.name from eg.Cat cat

select count(distinct cat.name), count(cat) from eg.Cat cat</pre>
								</div>
								<div class="sect1" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h2 class="title" style="CLEAR: both">
																		<a name="queryhql-polymorphism">
																		</a>11.6. 多态(polymorphism)查询</h2>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>类似下面的查询： </p>
										<pre class="programlisting">from eg.Cat as cat</pre>
										<p>返回的实例不仅仅是<tt class="literal">Cat</tt>，也有可能是子类的实例，比如<tt class="literal">DomesticCat</tt>。Hibernate查询可以在<tt class="literal">from</tt>子句中使用<span class="emphasis"><em>任何</em></span>Java类或者接口的名字。查询可能返回所有继承自这个类或者实现这个接口的持久化类的实例。下列查询会返回所有的持久化对象： </p>
										<pre class="programlisting">from java.lang.Object o</pre>
										<p>可能有多个持久化类都实现了<tt class="literal">Named</tt>接口： </p>
										<pre class="programlisting">from eg.Named n, eg.Named m where n.name = m.name</pre>
										<p>请注意，上面两个查询都使用了超过一个SQL的<tt class="literal">SELECT</tt>。这意味着<tt class="literal">order by</tt>子句将不会正确排序。（这也意味着你不能对这些查询使用<tt class="literal">Query.scroll()</tt>。） </p>
								</div>
								<div class="sect1" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h2 class="title" style="CLEAR: both">
																		<a name="queryhql-where">
																		</a>11.7. where子句</h2>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>
												<tt class="literal">where</tt>子句让你缩小你要返回的实例的列表范围。 </p>
										<pre class="programlisting">from eg.Cat as cat where cat.name='Fritz'</pre>
										<p>返回所有名字为'Fritz'的<tt class="literal">Cat</tt>的实例。 </p>
										<pre class="programlisting">select foo 
from eg.Foo foo, eg.Bar bar
where foo.startDate = bar.date</pre>
										<p>会返回所有的满足下列条件的<tt class="literal">Foo</tt>实例，它们存在一个对应的<tt class="literal">bar</tt>实例，其<tt class="literal">date</tt>属性与<tt class="literal">Foo</tt>的<tt class="literal">startDate</tt>属性相等。复合路径表达式令<tt class="literal">where</tt>子句变得极为有力。思考下面的例子： </p>
										<pre class="programlisting">from eg.Cat cat where cat.mate.name is not null</pre>
										<p>这个查询会被翻译为带有一个表间（inner)join的SQL查询。如果你写下类似这样的语句： </p>
										<pre class="programlisting">from eg.Foo foo  
where foo.bar.baz.customer.address.city is not null</pre>
										<p>你最终会得到的查询，其对应的SQL需要4个表间连接。 </p>
										<p>
												<tt class="literal">=</tt>操作符不仅仅用于判断属性是否相等，也可以用于实例： </p>
										<pre class="programlisting">from eg.Cat cat, eg.Cat rival where cat.mate = rival.mate

select cat, mate 
from eg.Cat cat, eg.Cat mate
where cat.mate = mate</pre>
										<p>特别的，小写的<tt class="literal">id</tt>可以用来表示一个对象的惟一标识。（你可以使用它的属性名。） </p>
										<pre class="programlisting">from eg.Cat as cat where cat.id = 123

from eg.Cat as cat where cat.mate.id = 69</pre>
										<p>第二个查询是很高效的。不需要进行表间连接！ </p>
										<p>组合的标示符也可以使用。假设<tt class="literal">Person</tt>有一个组合标示符，是由<tt class="literal">country</tt>和<tt class="literal">medicareNumber</tt>组合而成的。 </p>
										<pre class="programlisting">from bank.Person person
where person.id.country = 'AU' 
    and person.id.medicareNumber = 123456

from bank.Account account
where account.owner.id.country = 'AU' 
    and account.owner.id.medicareNumber = 123456</pre>
										<p>又一次，第二个查询不需要表间连接。 </p>
										<p>类似的，在存在多态持久化的情况下，特殊属性<tt class="literal">class</tt>用于获取某个实例的辨识值。在where子句中嵌入的Java类名将会转换为它的辨识值。 </p>
										<pre class="programlisting">from eg.Cat cat where cat.class = eg.DomesticCat</pre>
										<p>你也可以指定组件（或者是组件的组件，依次类推）或者组合类型中的属性。但是在一个存在路径的表达式中，最后不能以一个组件类型的属性结尾。（这里不是指组件的属性）。比如，假若<tt class="literal">store.owner</tt>这个实体的的<tt class="literal">address</tt>是一个组件 </p>
										<pre class="programlisting">store.owner.address.city    //okay
store.owner.address         //error!</pre>
										<p>“任意(any)”类型也有特殊的<tt class="literal">id</tt>属性和<tt class="literal">class</tt>属性，这可以让我们用下面的形式来表达连接（这里<tt class="literal">AuditLog.item</tt>是一个对应到<tt class="literal">&lt;ant&gt;</tt>的属性）。 </p>
										<pre class="programlisting">from eg.AuditLog log, eg.Payment payment 
where log.item.class = 'eg.Payment' and log.item.id = payment.id</pre>
										<p>注意上面查询中，<tt class="literal">log.item.class</tt>和<tt class="literal">payment.class</tt>会指向两个值，代表完全不同的数据库字段。 </p>
								</div>
								<div class="sect1" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h2 class="title" style="CLEAR: both">
																		<a name="queryhql-expressions">
																		</a>11.8. 表达式(Expressions)</h2>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>
												<tt class="literal">where</tt>子句允许出现的表达式包括了你在SQL中可以使用的大多数情况： </p>
										<div class="itemizedlist">
												<ul type="disc" compact="">
														<li>
																<p>数学操作<tt class="literal">+, -, *, /</tt></p>
														</li>
														<li>
																<p>真假比较操作 <tt class="literal">=, &gt;=, &lt;=, &lt;&gt;, !=, like</tt></p>
														</li>
														<li>
																<p>逻辑操作 <tt class="literal">and, or, not</tt></p>
														</li>
														<li>
																<p>字符串连接 || </p>
														</li>
														<li>
																<p>SQL标量（ scalar）函数，例如 <tt class="literal">upper()</tt> 和 <tt class="literal">lower()</tt></p>
														</li>
														<li>
																<p>没有前缀的 <tt class="literal">( )</tt>表示分组 </p>
														</li>
														<li>
																<p>
																		<tt class="literal">in</tt>, <tt class="literal">between</tt>, <tt class="literal">is null</tt></p>
														</li>
														<li>
																<p>JDBC 传入参数<tt class="literal">?</tt></p>
														</li>
														<li>
																<p>命名参数 <tt class="literal">:name</tt>, <tt class="literal">:start_date</tt>, <tt class="literal">:x1</tt></p>
														</li>
														<li>
																<p>SQL 文字 <tt class="literal">'foo'</tt>, <tt class="literal">69</tt>, <tt class="literal">'1970-01-01 10:00:01.0'</tt></p>
														</li>
														<li>
																<p>Java的<tt class="literal">public static final</tt>常量<tt class="literal"> 比如 Color.TABBY</tt></p>
														</li>
												</ul>
										</div>
										<p>
												<tt class="literal">in</tt> 和 <tt class="literal">between</tt> 可以如下例一样使用: </p>
										<pre class="programlisting">from eg.DomesticCat cat where cat.name between 'A' and 'B'

from eg.DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )</pre>
										<p>其否定形式为 </p>
										<pre class="programlisting">from eg.DomesticCat cat where cat.name not between 'A' and 'B'

from eg.DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )</pre>
										<p>类似的，<tt class="literal">is null</tt>和<tt class="literal">is not null</tt>可以用来测试null值。 </p>
										<p>通过在Hibernate配置中声明HQL查询的替换方式，Boolean也是很容易在表达式中使用的： </p>
										<pre class="programlisting">&lt;property name="hibernate.query.substitutions"&gt;true 1, false 0&lt;/property&gt;</pre>
										<p>在从HQL翻译成SQL的时候,关键字<tt class="literal">true</tt>和<tt class="literal">false</tt>就会被替换成<tt class="literal">1</tt>和<tt class="literal">0</tt>。 </p>
										<pre class="programlisting">from eg.Cat cat where cat.alive = true</pre>
										<p>你可以用特殊属性<tt class="literal">size</tt>来测试一个集合的长度，或者用特殊的<tt class="literal">size()</tt>函数也可以。 </p>
										<pre class="programlisting">from eg.Cat cat where cat.kittens.size &gt; 0

from eg.Cat cat where size(cat.kittens) &gt; 0</pre>
										<p>对于排序集合，你可以用<tt class="literal">minIndex</tt>和<tt class="literal">maxIndex</tt>来获取其最大索引值和最小索引值。类似的，<tt class="literal">minElement</tt> 和<tt class="literal">maxElement</tt> 可以用来获取集合中最小和最大的元素，前提是必须是基本类型的集合。 </p>
										<pre class="programlisting">from Calendar cal where cal.holidays.maxElement &gt; current date</pre>
										<p>也有函数的形式（和上面的形式不同，函数形式是大小写不敏感的）： </p>
										<pre class="programlisting">from Order order where maxindex(order.items) &gt; 100

from Order order where minelement(order.items) &gt; 10000</pre>
										<p>SQL中的<tt class="literal">any, some, all, exists, in</tt>功能也是支持的，前提是必须把集合的元素或者索引集作为它们的参数（使用<tt class="literal">element</tt>和<tt class="literal">indices</tt>函数），或者使用子查询的结果作为参数。 </p>
										<pre class="programlisting">select mother from eg.Cat as mother, eg.Cat as kit
where kit in elements(foo.kittens)

select p from eg.NameList list, eg.Person p
where p.name = some elements(list.names)

from eg.Cat cat where exists elements(cat.kittens)

from eg.Player p where 3 &gt; all elements(p.scores)

from eg.Show show where 'fizard' in indices(show.acts)</pre>
										<p>请注意这些设施：<tt class="literal">size</tt>,<tt class="literal">elements</tt>,<tt class="literal">indices</tt>,<tt class="literal">minIndex</tt>,<tt class="literal">maxIndex</tt>,<tt class="literal">minElement</tt>,<tt class="literal">maxElement</tt> 都有一些使用限制： </p>
										<div class="itemizedlist">
												<ul type="disc" compact="">
														<li>
																<p>在<tt class="literal">where</tt>子句中: 只对支持子查询的数据库有效 </p>
														</li>
														<li>
																<p>在<tt class="literal">select</tt>子句中：只有<tt class="literal">elements</tt>和<tt class="literal">indices</tt>有效 </p>
														</li>
												</ul>
										</div>
										<p>有序的集合(数组、list、map)的元素可以用索引来进行引用（只限于在where子句中） </p>
										<pre class="programlisting">from Order order where order.items[0].id = 1234

select person from Person person, Calendar calendar
where calendar.holidays['national day'] = person.birthDay
    and person.nationality.calendar = calendar

select item from Item item, Order order
where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11

select item from Item item, Order order
where order.items[ maxindex(order.items) ] = item and order.id = 11</pre>
										<p>
												<tt class="literal">[]</tt>中的表达式允许是另一个数学表达式。 </p>
										<pre class="programlisting">select item from Item item, Order order
where order.items[ size(order.items) - 1 ] = item</pre>
										<p>HQL也对一对多关联或者值集合提供内置的<tt class="literal">index()</tt>函数。 </p>
										<pre class="programlisting">select item, index(item) from Order order 
    join order.items item
where index(item) &lt; 5</pre>
										<p>底层数据库支持的标量SQL函数也可以使用 </p>
										<pre class="programlisting">from eg.DomesticCat cat where upper(cat.name) like 'FRI%'</pre>
										<p>假如以上的这些还没有让你信服的话，请想象一下下面的查询假若用SQL来写，会变得多么长，多么不可读： </p>
										<pre class="programlisting">select cust
from Product prod,
    Store store
    inner join store.customers cust
where prod.name = 'widget'
    and store.location.name in ( 'Melbourne', 'Sydney' )
    and prod = all elements(cust.currentOrder.lineItems)</pre>
										<p>
												<span class="emphasis">
														<em>提示：</em>
												</span>对应的SQL语句可能是这样的 </p>
										<pre class="programlisting">SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order
FROM customers cust,
    stores store,
    locations loc,
    store_customers sc,
    product prod
WHERE prod.name = 'widget'
    AND store.loc_id = loc.id
    AND loc.name IN ( 'Melbourne', 'Sydney' )
    AND sc.store_id = store.id
    AND sc.cust_id = cust.id
    AND prod.id = ALL(
        SELECT item.prod_id
        FROM line_items item, orders o
        WHERE item.order_id = o.id
            AND cust.current_order = o.id
    )</pre>
								</div>
								<div class="sect1" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h2 class="title" style="CLEAR: both">
																		<a name="queryhql-ordering">
																		</a>11.9. order by 子句</h2>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>查询返回的列表可以按照任何返回的类或者组件的属性排序： </p>
										<pre class="programlisting">from eg.DomesticCat cat
order by cat.name asc, cat.weight desc, cat.birthdate</pre>
										<p>
												<tt class="literal">asc</tt>和<tt class="literal">desc</tt>是可选的，分别代表升序或者降序。 </p>
								</div>
								<div class="sect1" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h2 class="title" style="CLEAR: both">
																		<a name="queryhql-grouping">
																		</a>11.10. group by 子句</h2>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>返回统计值的查询可以按照返回的类或者组件的任何属性排序： </p>
										<pre class="programlisting">select cat.color, sum(cat.weight), count(cat) 
from eg.Cat cat
group by cat.color

select foo.id, avg( elements(foo.names) ), max( indices(foo.names) ) 
from eg.Foo foo
group by foo.id</pre>
										<p>请注意：你可以在select子句中使用<tt class="literal">elements</tt>和<tt class="literal">indices</tt>指令，即使你的数据库不支持子查询也可以。 </p>
										<p>
												<tt class="literal">having</tt>子句也是允许的。 </p>
										<pre class="programlisting">select cat.color, sum(cat.weight), count(cat) 
from eg.Cat cat
group by cat.color 
having cat.color in (eg.Color.TABBY, eg.Color.BLACK)</pre>
										<p>在<tt class="literal">having</tt>子句中允许出现SQL函数和统计函数，当然这需要底层数据库支持才行。（比如说,MySQL就不支持） </p>
										<pre class="programlisting">select cat
from eg.Cat cat
    join cat.kittens kitten
group by cat
having avg(kitten.weight) &gt; 100
order by count(kitten) asc, sum(kitten.weight) desc</pre>
										<p>注意，<tt class="literal">group by</tt>子句和<tt class="literal">order by</tt>子句都不支持数学表达式。 </p>
								</div>
								<div class="sect1" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h2 class="title" style="CLEAR: both">
																		<a name="queryhql-subqueries">
																		</a>11.11. 子查询</h2>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>对于支持子查询的数据库来说，Hibernate支持在查询中嵌套子查询。子查询必须由圆括号包围（常常是在一个SQL统计函数中）。也允许关联子查询（在外部查询中作为一个别名出现的子查询）。 </p>
										<pre class="programlisting">from eg.Cat as fatcat 
where fatcat.weight &gt; ( 
    select avg(cat.weight) from eg.DomesticCat cat 
)

from eg.DomesticCat as cat 
where cat.name = some ( 
    select name.nickName from eg.Name as name 
)
    
from eg.Cat as cat 
where not exists ( 
    from eg.Cat as mate where mate.mate = cat 
)

from eg.DomesticCat as cat 
where cat.name not in ( 
    select name.nickName from eg.Name as name 
)</pre>
								</div>
								<div class="sect1" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h2 class="title" style="CLEAR: both">
																		<a name="queryhql-examples">
																		</a>11.12. HQL示例</h2>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>Hibernate查询可以非常强大复杂。实际上，强有力的查询语言是Hibernate的主要卖点之一。下面给出的示例与我在近期实际项目中使用的一些查询很类似。请注意你编写的查询大部分等都不会这么复杂！ </p>
										<p>下面的查询对特定的客户，根据给定的最小总计值（minAmount)，查询出所有未付订单，返回其订单号、货品总数、订单总金额，结果按照总金额排序。在决定价格的时候，参考当前目录。产生的SQL查询，在<tt class="literal">ORDER</tt>,<tt class="literal">ORDER_LINE</tt>,<tt class="literal">PRODUCT</tt>,<tt class="literal">CATALOG</tt>和<tt class="literal">PRICE</tt>表之间有四个内部连接和一个没有产生关联的字查询。 </p>
										<pre class="programlisting">select order.id, sum(price.amount), count(item)
from Order as order
    join order.lineItems as item
    join item.product as product,
    Catalog as catalog
    join catalog.prices as price
where order.paid = false
    and order.customer = :customer
    and price.product = product
    and catalog.effectiveDate &lt; sysdate
    and catalog.effectiveDate &gt;= all (
        select cat.effectiveDate 
        from Catalog as cat
        where cat.effectiveDate &lt; sysdate
    )
group by order
having sum(price.amount) &gt; :minAmount
order by sum(price.amount) desc</pre>
										<p>好家伙，真长！实际上，在现实生活中我并不是非常热衷于子查询，所以我的查询往往是这样的： </p>
										<pre class="programlisting">select order.id, sum(price.amount), count(item)
from Order as order
    join order.lineItems as item
    join item.product as product,
    Catalog as catalog
    join catalog.prices as price
where order.paid = false
    and order.customer = :customer
    and price.product = product
    and catalog = :currentCatalog
group by order
having sum(price.amount) &gt; :minAmount
order by sum(price.amount) desc</pre>
										<p>下面的查询统计付款记录处于每种状态中的数量，要排除所有处于<tt class="literal">AWAITING_APPROVAL</tt>状态的，或者最近一次状态更改是由当前用户做出的。它翻译成SQL查询后，在<tt class="literal">PAYMENT</tt>,<tt class="literal">PAYMENT_STATUS</tt>和<tt class="literal">PAYMENT_STATUS_CHANGE</tt>表之间包含两个内部连接和一个用于关联的子查询。 </p>
										<pre class="programlisting">select count(payment), status.name 
from Payment as payment 
    join payment.currentStatus as status
    join payment.statusChanges as statusChange
where payment.status.name &lt;&gt; PaymentStatus.AWAITING_APPROVAL
    or (
        statusChange.timeStamp = ( 
            select max(change.timeStamp) 
            from PaymentStatusChange change 
            where change.payment = payment
        )
        and statusChange.user &lt;&gt; :currentUser
    )
group by status.name, status.sortOrder
order by status.sortOrder</pre>
										<p>假若我已经把<tt class="literal">statusChange</tt>集合映射为一个列表而不是一个集合的话，查询写起来会简单很多。 </p>
										<pre class="programlisting">select count(payment), status.name 
from Payment as payment
    join payment.currentStatus as status
where payment.status.name &lt;&gt; PaymentStatus.AWAITING_APPROVAL
    or payment.statusChanges[ maxIndex(payment.statusChanges) ].user &lt;&gt; :currentUser
group by status.name, status.sortOrder
order by status.sortOrder</pre>
										<p>下面的查询使用了MS SQL Server的<tt class="literal">isNull()</tt>函数，返回当前用户所属的组织所有账户和未付支出。翻译为SQL查询后，在<tt class="literal">ACCOUNT</tt>, <tt class="literal">PAYMENT</tt>, <tt class="literal">PAYMENT_STATUS</tt>,<tt class="literal">ACCOUNT_TYPE</tt>, <tt class="literal">ORGANIZATION</tt> 和 <tt class="literal">ORG_USER</tt>表之间有三个内部连接，一个外部连接和一个子查询。 </p>
										<pre class="programlisting">select account, payment
from Account as account
    left outer join account.payments as payment
where :currentUser in elements(account.holder.users)
    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
order by account.type.sortOrder, account.accountNumber, payment.dueDate</pre>
										<p>对某些数据库而言，我们可能不能依赖（关联的）子查询。 </p>
										<pre class="programlisting">select account, payment
from Account as account
    join account.holder.users as user
    left outer join account.payments as payment
where :currentUser = user
    and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID)
order by account.type.sortOrder, account.accountNumber, payment.dueDate</pre>
								</div>
								<div class="sect1" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h2 class="title" style="CLEAR: both">
																		<a name="queryhql-tipstricks">
																		</a>11.13. 提示和技巧（Tips &amp; Tricks）</h2>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>你不返回结果集也可以查询结果集的大小： </p>
										<pre class="programlisting">( (Integer) session.iterate("select count(*) from ....").next() ).intValue()</pre>
										<p>要依据一个集合的大小对结果集排序，可以用下面的查询来对付一对多或多对多的关联： </p>
										<pre class="programlisting">select usr
from User as usr 
    left join usr.messages as msg
group by usr
order by count(msg)</pre>
										<p>如果你的数据库支持子查询，你可以在查询的where子句中对选择的大小进行条件限制： </p>
										<pre class="programlisting">from User usr where size(usr.messages) &gt;= 1</pre>
										<p>如果你的数据库不支持子查询，可以使用下列查询： </p>
										<pre class="programlisting">select usr.id, usr.name
from User usr.name
    join usr.messages msg
group by usr.id, usr.name
having count(msg) &gt;= 1</pre>
										<p>因为使用了inner join,这个解决方法不能返回没有message的<tt class="literal">User</tt>.下面的方式就可以： </p>
										<pre class="programlisting">select usr
from User as usr
    left join usr.messages as msg
group by usr
having count(msg) = 0</pre>
										<p>JavaBean的属性可以直接作为命名的查询参数： </p>
										<pre class="programlisting">Query q = s.createQuery("from foo in class Foo where foo.name=:name and foo.size=:size");
q.setProperties(fooBean); // fooBean has getName() and getSize()
List foos = q.list();</pre>
										<p>在<tt class="literal">Query</tt>接口中使用过滤器(filter),可以对集合分页： </p>
										<pre class="programlisting">Query q = s.createFilter( collection, "" ); // the trivial filter
q.setMaxResults(PAGE_SIZE);
q.setFirstResult(PAGE_SIZE * pageNumber);
List page = q.list();</pre>
										<p>集合元素可以使用查询过滤器(query filter)进行排序或者分组： </p>
										<pre class="programlisting">Collection orderedCollection = s.filter( collection, "order by this.amount" );
Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );</pre>
										<p>不用初始化集合就可以得到其大小： </p>
										<pre class="programlisting">( (Integer) session.iterate("select count(*) from ....").next() ).intValue();</pre>
								</div>
						</div>
						<div class="navfooter">
								<hr />
								<table width="100%" summary="Navigation footer">
										<tbody>
												<tr>
														<td align="left" width="40%">
																<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/transactions.html">
																		<font color="#002c99">上一页</font>
																</a> </td>
														<td align="middle" width="20%">
																<a accesskey="u" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
																		<font color="#002c99">上一级</font>
																</a>
														</td>
														<td align="right" width="40%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/querycriteria.html"><font color="#002c99">下一页</font></a></td>
												</tr>
												<tr>
														<td valign="top" align="left" width="40%">第 10 章 事务和并行（Transactions And Concurrency） </td>
														<td align="middle" width="20%">
																<a accesskey="h" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
																		<font color="#002c99">起始页</font>
																</a>
														</td>
														<td valign="top" align="right" width="40%"> 第 12 章 条件查询(Criteria Query)</td>
												</tr>
										</tbody>
								</table>
						</div>
				</div>
		</div>
<img src ="http://www.cnitblog.com/forrest/aggbug/16231.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2006-08-31 18:39 <a href="http://www.cnitblog.com/forrest/articles/16231.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第 8 章 继承映射(Inheritance Mappings)  第 9 章 操作持久化数据(Manipulating Persistent Data)</title><link>http://www.cnitblog.com/forrest/articles/16230.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Thu, 31 Aug 2006 10:38:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/articles/16230.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/16230.html</wfw:comment><comments>http://www.cnitblog.com/forrest/articles/16230.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/16230.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/16230.html</trackback:ping><description><![CDATA[
		<div class="navheader">
				<table width="100%" summary="Navigation header">
						<tbody>
								<tr>
										<th align="middle" colspan="3">第 8 章 继承映射(Inheritance Mappings)</th>
								</tr>
								<tr>
										<td align="left" width="20%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/components.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<th align="middle" width="60%"> </th>
										<td align="right" width="20%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/manipulatingdata.html"><font color="#002c99">下一页</font></a></td>
								</tr>
						</tbody>
				</table>
				<font color="#002c99">
						<hr />
				</font>
		</div>
		<div class="chapter" lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h2 class="title">
												<a name="inheritance">
												</a>第 8 章 继承映射(Inheritance Mappings)</h2>
								</div>
						</div>
						<div>
						</div>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="inheritance-strategies">
														</a>8.1. 三种策略</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>Hibernate支持三种不同的基本继承映射策略。 </p>
						<div class="itemizedlist">
								<ul type="disc">
										<li>
												<p>每棵类继承树使用一个表(table per class hierarchy) </p>
										</li>
										<li>
												<p>每个子类一个表(table per subclass) </p>
										</li>
										<li>
												<p>每个具体类一个表(table per concrete class)（有一些限制） </p>
										</li>
								</ul>
						</div>
						<p>甚至在一棵继承关系书中对不同的分支使用不同的映射策略也是可能的。但是和“每个具体类一个表”的映射有一样的限制。Hibernate不支持把<tt class="literal">&lt;subclass&gt;</tt>映射与<tt class="literal">&lt;joined-subclass&gt;</tt>在同一个<tt class="literal">&lt;class&gt;</tt> 元素中混合使用。 </p>
						<p>假设我们有一个<tt class="literal">Payment</tt>接口，有不同的实现：<tt class="literal">CreditCardPayment</tt>, <tt class="literal">CashPayment</tt>, <tt class="literal">ChequePayment</tt>。“继承数共享一个表”的映射是这样的： </p>
						<pre class="programlisting">&lt;class name="Payment" table="PAYMENT"&gt;
    &lt;id name="id" type="long" column="PAYMENT_ID"&gt;
        &lt;generator class="native"/&gt;
    &lt;/id&gt;
    &lt;discriminator column="PAYMENT_TYPE" type="string"/&gt;
    &lt;property name="amount" column="AMOUNT"/&gt;
    ...
    &lt;subclass name="CreditCardPayment" discriminator-value="CREDIT"&gt;
        ...
    &lt;/subclass&gt;
    &lt;subclass name="CashPayment" discriminator-value="CASH"&gt;
        ...
    &lt;/subclass&gt;
    &lt;subclass name="ChequePayment" discriminator-value="CHEQUE"&gt;
        ...
    &lt;/subclass&gt;
&lt;/class&gt;</pre>
						<p>只需要一个表。这种映射策略由一个大限制：子类定义的字段不能有<tt class="literal">NOT NULL</tt>限制。 </p>
						<p>“每个子类一个表”的映射是这样的： </p>
						<pre class="programlisting">&lt;class name="Payment" table="PAYMENT"&gt;
    &lt;id name="id" type="long" column="PAYMENT_ID"&gt;
        &lt;generator class="native"/&gt;
    &lt;/id&gt;
    &lt;property name="amount" column="AMOUNT"/&gt;
    ...
    &lt;joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT"&gt;
        &lt;key column="PAYMENT_ID"/&gt;
        ...
    &lt;/joined-subclass&gt;
    &lt;joined-subclass name="CashPayment" table="CASH_PAYMENT"&gt;
        &lt;key column="PAYMENT_ID"/&gt;
        ...
    &lt;/joined-subclass&gt;
    &lt;joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT"&gt;
        &lt;key column="PAYMENT_ID"/&gt;
        ...
    &lt;/joined-subclass&gt;
&lt;/class&gt;</pre>
						<p>需要四个表。三个子类表通过主键和超类表关联（所以实际上关系模型是一对一关联）。 </p>
						<p>注意Hibernate的“每子类一表”的实现并不需要一个特别的辨认字段。其他的对象/关系数据库映射工具使用另一种“每子类一表”实现，需要在超类表中有一个类型辨认字段。Hibernate的这种实现更加困难，但是从关系(数据库)的角度来看，这样做更加正确。 </p>
						<p>对这两种映射策略来说，指向<tt class="literal">Payment</tt>的关联是使用<tt class="literal">&lt;many-to-one&gt;</tt>进行映射的。 </p>
						<pre class="programlisting">&lt;many-to-one name="payment"
    column="PAYMENT"
    class="Payment"/&gt;</pre>
						<p>“每个具体类一个表”的策略非常不同</p>
						<pre class="programlisting">&lt;class name="CreditCardPayment" table="CREDIT_PAYMENT"&gt;
    &lt;id name="id" type="long" column="CREDIT_PAYMENT_ID"&gt;
        &lt;generator class="native"/&gt;
    &lt;/id&gt;
    &lt;property name="amount" column="CREDIT_AMOUNT"/&gt;
    ...
&lt;/class&gt;

&lt;class name="CashPayment" table="CASH_PAYMENT"&gt;
    &lt;id name="id" type="long" column="CASH_PAYMENT_ID"&gt;
        &lt;generator class="native"/&gt;
    &lt;/id&gt;
    &lt;property name="amount" column="CASH_AMOUNT"/&gt;
    ...
&lt;/class&gt;

&lt;class name="ChequePayment" table="CHEQUE_PAYMENT"&gt;
    &lt;id name="id" type="long" column="CHEQUE_PAYMENT_ID"&gt;
        &lt;generator class="native"/&gt;
    &lt;/id&gt;
    &lt;property name="amount" column="CHEQUE_AMOUNT"/&gt;
    ...
&lt;/class&gt;</pre>
						<p>需要三个表。注意我们没有明确的定义<tt class="literal">Payment</tt>接口。我们用Hibernate的<span class="emphasis"><em>隐含多态（implicit polymorphism）</em></span>机制代替。也要注意<tt class="literal">Payment</tt>的属性在三个字类中都进行了映射。 </p>
						<p>这种情形下，与<tt class="literal">Payment</tt>关联的多态关联被映射为<tt class="literal">&lt;any&gt;</tt>。 </p>
						<pre class="programlisting">&lt;any name="payment" 
        meta-type="class"
        id-type="long"&gt;
    &lt;column name="PAYMENT_CLASS"/&gt;
    &lt;column name="PAYMENT_ID"/&gt;
&lt;/any&gt;</pre>
						<p>如果我们定义<tt class="literal">UserType</tt>和<tt class="literal">meta-type</tt>来根据不同的标识字符串映射到<tt class="literal">Payment</tt>，事情会更好一些。 </p>
						<pre class="programlisting">&lt;any name="payment" 
        meta-type="PaymentMetaType"
        id-type="long"&gt;
    &lt;column name="PAYMENT_TYPE"/&gt; &lt;!-- CREDIT, CASH or CHEQUE --&gt;
    &lt;column name="PAYMENT_ID"/&gt;
&lt;/any&gt;</pre>
						<p>对这个映射还有一点需要注意。因为每个子类都在各自独立的<tt class="literal">&lt;class&gt;</tt>元素中映射（并且<tt class="literal">Payment</tt>只是个接口），每个子类都可以和容易的成为另一个"每个类一个表"或者"每个子类一个表"的继承树！（并且你仍然可以对<tt class="literal">Payment</tt>接口使用多态查询。） </p>
						<pre class="programlisting">&lt;class name="CreditCardPayment" table="CREDIT_PAYMENT"&gt;
    &lt;id name="id" type="long" column="CREDIT_PAYMENT_ID"&gt;
        &lt;generator class="native"/&gt;
    &lt;/id&gt;
    &lt;discriminator column="CREDIT_CARD" type="string"/&gt;
    &lt;property name="amount" column="CREDIT_AMOUNT"/&gt;
    ...
    &lt;subclass name="MasterCardPayment" discriminator-value="MDC"/&gt;
    &lt;subclass name="VisaPayment" discriminator-value="VISA"/&gt;
&lt;/class&gt;

&lt;class name="NonelectronicTransaction" table="NONELECTRONIC_TXN"&gt;
    &lt;id name="id" type="long" column="TXN_ID"&gt;
        &lt;generator class="native"/&gt;
    &lt;/id&gt;
    ...
    &lt;joined-subclass name="CashPayment" table="CASH_PAYMENT"&gt;
        &lt;key column="PAYMENT_ID"/&gt;
        &lt;property name="amount" column="CASH_AMOUNT"/&gt;
        ...
    &lt;/joined-subclass&gt;
    &lt;joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT"&gt;
        &lt;key column="PAYMENT_ID"/&gt;
        &lt;property name="amount" column="CHEQUE_AMOUNT"/&gt;
        ...
    &lt;/joined-subclass&gt;
&lt;/class&gt;</pre>
						<p>我们再一次没有明确的提到<tt class="literal">Payment</tt>。如果我们针对<tt class="literal">Payment</tt>接口执行查询 ——比如，<tt class="literal">from Payment</tt>—— Hibernate自动返回<tt class="literal">CreditCardPayment</tt>实例（以及它的子类，因为它们也继承了<tt class="literal">Payment</tt>），<tt class="literal">CashPayment</tt>和<tt class="literal">Chequepayment</tt>，但是不会是<tt class="literal">NonelectronicTransaction</tt>的实例。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="inheritance-limitations">
														</a>8.2. 限制</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>Hibernate假设关联严格的和一个外键字段相映射。如果一个外键具有多个关联，也是可以容忍的（你可能需要指定<tt class="literal">inverse="true"</tt>或者<tt class="literal">insert="false" update="false"</tt>），但是你不能为多重外键指定任何映射的关联。这意味着： </p>
						<div class="itemizedlist">
								<ul type="disc">
										<li>
												<p>当更改一个关联的时候，永远是更新的同一个外键 </p>
										</li>
										<li>
												<p>当一个关联是延迟抓取(fetched lazily)的时候，只需要用一次数据库查询 </p>
										</li>
										<li>
												<p>当一个关联是提前抓取(fetched eagerly)的时候，使用一次outer join即可 </p>
										</li>
								</ul>
						</div>
						<p>特别要指出的是，使用“每个具体类一个表”的策略来实行多态的一对多关联是<span class="emphasis"><em>不支持</em></span>的。（抓取这样的关联需要多次查询或者多次join。） </p>
						<p>下面的表格列出了Hibernte中，“每个具体类一个表”策略与隐含多态机制的限制。 </p>
						<div class="table">
								<a name="d0e5663">
								</a>
								<p class="title">
										<b>表 8.1. 继承映射特性（Features of inheritance mappings） </b>
								</p>
								<table summary="继承映射特性（Features of inheritance mappings）			" border="1">
										<colgroup>
												<col align="left" />
												<col align="left" />
												<col align="left" />
												<col align="left" />
												<col align="left" />
												<col align="left" />
												<col align="left" />
												<col align="left" />
										</colgroup>
										<thead>
												<tr>
														<th align="left">继承策略（Inheritance strategy）</th>
														<th align="left">多态多对一</th>
														<th align="left">多态一对一</th>
														<th align="left">多态一对多</th>
														<th align="left">多态多对多</th>
														<th align="left">多态 <tt class="literal">load()/get()</tt></th>
														<th align="left">多态查询</th>
														<th align="left">多态连接(join)</th>
														<th align="left">Outer join 抓取</th>
												</tr>
										</thead>
										<tbody>
												<tr>
														<td align="left">每继承树一表</td>
														<td align="left">
																<tt class="literal">&lt;many-to-one&gt;</tt>
														</td>
														<td align="left">
																<tt class="literal">&lt;one-to-one&gt;</tt>
														</td>
														<td align="left">
																<tt class="literal">&lt;one-to-many&gt;</tt>
														</td>
														<td align="left">
																<tt class="literal">&lt;many-to-many&gt;</tt>
														</td>
														<td align="left">
																<tt class="literal">s.get(Payment.class, id)</tt>
														</td>
														<td align="left">
																<tt class="literal">from Payment p</tt>
														</td>
														<td align="left">
																<tt class="literal">from Order o join o.payment p</tt>
														</td>
														<td align="left">
																<span class="emphasis">
																		<em>支持</em>
																</span>
														</td>
												</tr>
												<tr>
														<td align="left">每子类一表</td>
														<td align="left">
																<tt class="literal">&lt;many-to-one&gt;</tt>
														</td>
														<td align="left">
																<tt class="literal">&lt;one-to-one&gt;</tt>
														</td>
														<td align="left">
																<tt class="literal">&lt;one-to-many&gt;</tt>
														</td>
														<td align="left">
																<tt class="literal">&lt;many-to-many&gt;</tt>
														</td>
														<td align="left">
																<tt class="literal">s.get(Payment.class, id)</tt>
														</td>
														<td align="left">
																<tt class="literal">from Payment p</tt>
														</td>
														<td align="left">
																<tt class="literal">from Order o join o.payment p</tt>
														</td>
														<td align="left">
																<span class="emphasis">
																		<em>支持</em>
																</span>
														</td>
												</tr>
												<tr>
														<td align="left">每具体类一表(隐含多态)</td>
														<td align="left">
																<tt class="literal">&lt;any&gt;</tt>
														</td>
														<td align="left">
																<span class="emphasis">
																		<em>不支持</em>
																</span>
														</td>
														<td align="left">
																<span class="emphasis">
																		<em>不支持</em>
																</span>
														</td>
														<td align="left">
																<tt class="literal">&lt;many-to-any&gt;</tt>
														</td>
														<td align="left">
																<span class="emphasis">
																		<em>use a query</em>
																</span>
														</td>
														<td align="left">
																<tt class="literal">from Payment p</tt>
														</td>
														<td align="left">
																<span class="emphasis">
																		<em>不支持</em>
																</span>
														</td>
														<td align="left">
																<span class="emphasis">
																		<em>不支持</em>
																</span>
														</td>
												</tr>
										</tbody>
								</table>
						</div>
				</div>
		</div>
		<div class="navfooter">
				<hr />
				<table width="100%" summary="Navigation footer">
						<tbody>
								<tr>
										<td align="left" width="40%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/components.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<td align="middle" width="20%">
												<a accesskey="u" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">上一级</font>
												</a>
										</td>
										<td align="right" width="40%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/manipulatingdata.html"><font color="#002c99">下一页</font></a></td>
								</tr>
								<tr>
										<td valign="top" align="left" width="40%">第 7 章 组件（Component）映射 </td>
										<td align="middle" width="20%">
												<a accesskey="h" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">起始页</font>
												</a>
										</td>
										<td valign="top" align="right" width="40%"> 第 9 章 操作持久化数据(Manipulating Persistent Data)</td>
								</tr>
						</tbody>
				</table>
				<br />
				<div class="navheader">
						<table width="100%" summary="Navigation header">
								<tbody>
										<tr>
												<th align="middle" colspan="3">第 9 章 操作持久化数据(Manipulating Persistent Data)</th>
										</tr>
										<tr>
												<td align="left" width="20%">
														<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/inheritance.html">
																<font color="#002c99">上一页</font>
														</a> </td>
												<th align="middle" width="60%"> </th>
												<td align="right" width="20%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/transactions.html"><font color="#002c99">下一页</font></a></td>
										</tr>
								</tbody>
						</table>
						<font color="#002c99">
								<hr />
						</font>
				</div>
				<div class="chapter" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title">
														<a name="manipulatingdata">
														</a>第 9 章 操作持久化数据(Manipulating Persistent Data)</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<div class="sect1" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h2 class="title" style="CLEAR: both">
																<a name="manipulatingdata-creating">
																</a>9.1. 创建一个持久化对象</h2>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>对象（实体的实例）对一个特定的<tt class="literal">Session</tt>来说，要么是一个<span class="emphasis"><em>瞬时（transient）</em></span>对象，要么是<tt class="literal">持久化（persistent）</tt>对象。刚刚创建的对象当然是瞬时的(注：后文中transient object也称为临时对象)。session则提供了把瞬时实例保存（持久化）的服务: </p>
								<pre class="programlisting">DomesticCat fritz = new DomesticCat();
fritz.setColor(Color.GINGER);
fritz.setSex('M');
fritz.setName("Fritz");
Long generatedId = (Long) sess.save(fritz);</pre>
								<pre class="programlisting">DomesticCat pk = new DomesticCat();
pk.setColor(Color.TABBY);
pk.setSex('F');
pk.setName("PK");
pk.setKittens( new HashSet() );
pk.addKitten(fritz);
sess.save( pk, new Long(1234) );</pre>
								<p>单参数的<tt class="literal">save()</tt>方法为<tt class="literal">fritz</tt>生成了一个惟一标识符，并赋给这个对象。双参数的形式则使用给定的标识符保存<tt class="literal">pk</tt>。我们一般不鼓励使用双参数的形式，因为这可能会（隐含）使主键赋予业务含义。它有用的时候是在一些特殊场合下，比如使用Hibernate来持久化一个BMP实体bean. </p>
								<p>关联的对象可以用你喜欢的任何顺序持久化，除非有外键字段具有<tt class="literal">NOT NULL</tt>的约束。决不会有外键约束冲突的危险。然而，如果在<tt class="literal">save()</tt>对象的时候用错了顺序，会触犯<tt class="literal">NOT NULL</tt>约束。 </p>
						</div>
						<div class="sect1" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h2 class="title" style="CLEAR: both">
																<a name="manipulatingdata-loading">
																</a>9.2. 装载对象</h2>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>如果你已知某个持久化实例的标识符，<tt class="literal">Session</tt>的<tt class="literal">load()</tt>方法让你取出它。第一种形式使用一个类对象作为参数，会把状态装载到另一个新创建的对象中去。第二个版本允许你给出一个实例，会在其中装载状态。把实例作为参数的形式在你准备把Hibernate和BMP实体bean一起使用的时候特别有用，它就是为此设计的。你也可以发现其他的用途（比如自己实现实例池等等）。 </p>
								<pre class="programlisting">Cat fritz = (Cat) sess.load(Cat.class, generatedId);</pre>
								<pre class="programlisting">// you need to wrap primitive identifiers
long pkId = 1234;
DomesticCat pk = (DomesticCat) sess.load( Cat.class, new Long(pkId) );</pre>
								<pre class="programlisting">Cat cat = new DomesticCat();
// load pk''s state into cat
sess.load( cat, new Long(pkId) );
Set kittens = cat.getKittens();</pre>
								<p>请注意如果没有匹配的数据库记录，<tt class="literal">load()</tt>方法可能抛出无法恢复的exception。如果类是通过代理映射的，<tt class="literal">load()</tt>方法返回一个对象，这是一个未初始化的代理，并且直到你调用该对象的某方法时才会去访问数据库。这种行为方式在你喜欢创建一个指向某对象的关联，又不想真的从数据库中装载它的时候特别有用。 </p>
								<p>如果你不确定是否有匹配的行存在，你应该使用<tt class="literal">get()</tt>方法，它会立刻访问数据库，如果没有对应的行，返回null。 </p>
								<pre class="programlisting">Cat cat = (Cat) sess.get(Cat.class, id);
if (cat==null) {
    cat = new Cat();
    sess.save(cat, id);
}
return cat;</pre>
								<p>你可以用SQL<tt class="literal">SELECT ... FOR UPDATE</tt>装载对象。下一节有关于Hibernate <tt class="literal">LockMode</tt>的讨论。 </p>
								<pre class="programlisting">Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);</pre>
								<p>注意，任何关联的实例或者包含的集合都<span class="emphasis"><em>不会</em></span>被做为<tt class="literal">FOR UPDATE</tt>返回。 </p>
								<p>任何时候都可以使用<tt class="literal">refresh()</tt>方法重新装载对象和它的集合。如果你使用数据库触发器更改了对象的某些属性，这就很有用。 </p>
								<pre class="programlisting">sess.save(cat);
sess.flush(); //force the SQL INSERT
sess.refresh(cat); //re-read the state (after the trigger executes)</pre>
						</div>
						<div class="sect1" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h2 class="title" style="CLEAR: both">
																<a name="manipulatingdata-querying">
																</a>9.3. Querying</h2>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>如果你不能确定你要寻找的对象的标示符，请使用<tt class="literal">Session</tt>的<tt class="literal">find()</tt>方法。Hibernate使用一种简单而强大的面向对象查询语言。 </p>
								<pre class="programlisting">List cats = sess.find(
    "from Cat as cat where cat.birthdate = ?",
    date,
    Hibernate.DATE
);

List mates = sess.find(
    "select mate from Cat as cat join cat.mate as mate " +
    "where cat.name = ?",
    name,
    Hibernate.STRING
);

List cats = sess.find( "from Cat as cat where cat.mate.bithdate is null" );

List moreCats = sess.find(
    "from Cat as cat where " + 
    "cat.name = 'Fritz' or cat.id = ? or cat.id = ?",
    new Object[] { id1, id2 },
    new Type[] { Hibernate.LONG, Hibernate.LONG }
);

List mates = sess.find(
    "from Cat as cat where cat.mate = ?",
    izi,
    Hibernate.entity(Cat.class)
);

List problems = sess.find(
    "from GoldFish as fish " +
    "where fish.birthday &gt; fish.deceased or fish.birthday is null"
);</pre>
								<p>
										<tt class="literal">find()</tt>的第二个参数接受一个对象或者对象数组。第三个参数接受一个Hibernate类型或者类型的数组。这些指定的类型用来把给定的对象绑定到查询中的<tt class="literal">?</tt>占位符（实际上对应的是JDBC <tt class="literal">PreparedStatement</tt>的传入参数）。就像在JDBC中一眼，你应该优先使用这种参数绑定的方式，而非组装字符串。 </p>
								<p>
										<tt class="literal">Hibernate</tt>类定义了一些静态方法和常量，提供了访问大部分内置类型的手段。这些内置类型是<tt class="literal">net.sf.hibernate.type.Type</tt>的实例。 </p>
								<p>如果你知道你的查询会返回非常大量的对象，但是你不希望全部使用它们，你可以用<tt class="literal">iterate()</tt>方法获得更好的性能，它会返回一个<tt class="literal">java.util.Iterator</tt>。这个迭代器会在需要的时候装载对象，所使用的标识符来自一个前导的SQL查询。(一共是N+1次查询） </p>
								<pre class="programlisting">// fetch ids
Iterator iter = sess.iterate("from eg.Qux q order by q.likeliness"); 
while ( iter.hasNext() ) {
    Qux qux = (Qux) iter.next();  // fetch the object
    // something we couldnt express in the query
    if ( qux.calculateComplicatedAlgorithm() ) {
        // delete the current instance
        iter.remove();
        // dont need to process the rest
        break;
    }
}</pre>
								<p>很不幸，<tt class="literal">java.util.Iterator</tt>没有声明任何exception。所以，发生的任何SQL或者Hibernate的exception都会被包装在一个<tt class="literal">LazyInitializationException</tt>中（它是<tt class="literal">RuntimeException</tt>的子类）。 </p>
								<p>如果你预期大部分的对象已经装载过，存在于session的缓存中了，或者查询结果包含同样的对象很多次，那么<tt class="literal">iterator()</tt>方法也会获得更好的性能。（如果没有任何数据被缓存或者重复出现，则<tt class="literal">find()</tt>总是会更快。）下面是一个应该使用<tt class="literal">iterator()</tt>调用的查询例子： </p>
								<pre class="programlisting">Iterator iter = sess.iterate(
    "select customer, product " + 
    "from Customer customer, " +
    "Product product " +
    "join customer.purchases purchase " +
    "where product = purchase.product"
);</pre>
								<p>如果对上面的查询使用<tt class="literal">find()</tt>，会返回一个非常大的JDBC<tt class="literal">ResultSet</tt>,包含很多重复的相同数据。 </p>
								<p>有时候Hibernate查询会每行返回多种对象，这种情况下，每行会返回一个数组，包含多个对象元素： </p>
								<pre class="programlisting">Iterator foosAndBars = sess.iterate(
    "select foo, bar from Foo foo, Bar bar " +
    "where bar.date = foo.date"
);
while ( foosAndBars.hasNext() ) {
    Object[] tuple = (Object[]) foosAndBars.next();
    Foo foo = tuple[0]; Bar bar = tuple[1];
    ....
}</pre>
								<div class="sect2" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h3 class="title">
																		<a name="manipulatingdata-scalarqueries">
																		</a>9.3.1. 标量查询（Scalar query）</h3>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>查询可以在<tt class="literal">select</tt>子句中指定类的属性。甚至可以调用SQL的统计函数。属性或者统计值被称为“标量(scalar)”结果。 </p>
										<pre class="programlisting">Iterator results = sess.iterate(
        "select cat.color, min(cat.birthdate), count(cat) from Cat cat " +
        "group by cat.color"
);
while ( results.hasNext() ) {
    Object[] row = results.next();
    Color type = (Color) row[0];
    Date oldest = (Date) row[1];
    Integer count = (Integer) row[2];
    .....
}</pre>
										<pre class="programlisting">Iterator iter = sess.iterate(
    "select cat.type, cat.birthdate, cat.name from DomesticCat cat"
);</pre>
										<pre class="programlisting">List list = sess.find(
    "select cat, cat.mate.name from DomesticCat cat"
);</pre>
								</div>
								<div class="sect2" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h3 class="title">
																		<a name="manipulatingdata-queryinterface">
																		</a>9.3.2. 查询接口（Query interface）</h3>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>如果你需要为你的结果集设置边界（你需要获取的最大行数与/或你希望获取的第一行），你应该得到一个<tt class="literal">net.sf.hibernate.Query</tt>的实例： </p>
										<pre class="programlisting">Query q = sess.createQuery("from DomesticCat cat");
q.setFirstResult(20);
q.setMaxResults(10);
List cats = q.list();</pre>
										<p>你甚至可以在映射文档中定义命名查询。（记得用一个<tt class="literal">CDATA</tt>块把你的查询包含起来，否则在分析的时候可能引起误解。） </p>
										<pre class="programlisting">&lt;query name="eg.DomesticCat.by.name.and.minimum.weight"&gt;&lt;![CDATA[
    from eg.DomesticCat as cat
        where cat.name = ?
        and cat.weight &gt; ?
] ]&gt;&lt;/query&gt;</pre>
										<pre class="programlisting">Query q = sess.getNamedQuery("eg.DomesticCat.by.name.and.minimum.weight");
q.setString(0, name);
q.setInt(1, minWeight);
List cats = q.list();</pre>
										<p>查询界面支持使用命名参数。命名参数用<tt class="literal">:name</tt>的形式在查询字符串中表示。在<tt class="literal">Query</tt>中有方法把实际参数绑定到命名参数或者JDBC风格的<tt class="literal">?</tt>参数。<span class="emphasis"><em> 和JDBC不同，Hibernate的参数从0开始计数。</em></span> 使用命名参数有一些好处： </p>
										<div class="itemizedlist">
												<ul type="disc" compact="">
														<li>
																<p>命名参数不依赖于它们在查询字符串中出现的顺序 </p>
														</li>
														<li>
																<p>在同一个查询中可以使用多次 </p>
														</li>
														<li>
																<p>他们可读性好 </p>
														</li>
												</ul>
										</div>
										<pre class="programlisting">//named parameter (preferred)
Query q = sess.createQuery("from DomesticCat cat where cat.name = :name");
q.setString("name", "Fritz");
Iterator cats = q.iterate();</pre>
										<pre class="programlisting">//positional parameter
Query q = sess.createQuery("from DomesticCat cat where cat.name = ?");
q.setString(0, "Izi");
Iterator cats = q.iterate();</pre>
										<pre class="programlisting">//named parameter list
List names = new ArrayList();
names.add("Izi");
names.add("Fritz");
Query q = sess.createQuery("from DomesticCat cat where cat.name in (:namesList)");
q.setParameterList("namesList", names);
List cats = q.list();</pre>
								</div>
								<div class="sect2" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h3 class="title">
																		<a name="manipulatingdata-scrolling">
																		</a>9.3.3. 可滚动迭代(Scrollable iteration)</h3>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>如果你的JDBC驱动支持可滚动的<tt class="literal">ResuleSet</tt>,<tt class="literal">Query</tt>接口可以获取一个<tt class="literal">ScrollableResults</tt>，允许你在查询结果中灵活游走。 </p>
										<pre class="programlisting">Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " +
                            "order by cat.name");
ScrollableResults cats = q.scroll();
if ( cats.first() ) {

    // find the first name on each page of an alphabetical list of cats by name
    firstNamesOfPages = new ArrayList();
    do {
        String name = cats.getString(0);
        firstNamesOfPages.add(name);
    }
    while ( cats.scroll(PAGE_SIZE) );

    // Now get the first page of cats
    pageOfCats = new ArrayList();
    cats.beforeFirst();
    int i=0;
    while( ( PAGE_SIZE &gt; i++ ) &amp;&amp; cats.next() ) pageOfCats.add( cats.get(1) );

}</pre>
										<p>
												<tt class="literal">scroll()</tt>的行为方式与<tt class="literal">iterate()</tt>很类似，除了对象可以有选择的用<tt class="literal">get(int)</tt>初始化，而非整个行都一次性被初始化。 </p>
								</div>
								<div class="sect2" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h3 class="title">
																		<a name="manipulatingdata-filtering">
																		</a>9.3.4. 过滤集合类(Filtering collections)</h3>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>集合<span class="emphasis"><em>filter</em></span>是一种特殊的查询，用于一个持久化集合或者数组。查询字符串可以引用<tt class="literal">this</tt>,意为当前的数组元素。 </p>
										<pre class="programlisting">Collection blackKittens = session.filter( 
    pk.getKittens(), "where this.color = ?", Color.BLACK, Hibernate.enum(Color.class)
);</pre>
										<p>返回的集合被认为是一个包(bag)。 </p>
										<p>请注意filter并不需要<tt class="literal">from</tt> 子句（当然需要的话它们也可以加上）。Filter不限定返回它们自己的集合元素。 </p>
										<pre class="programlisting">Collection blackKittenMates = session.filter( 
    pk.getKittens(), "select this.mate where this.color = eg.Color.BLACK"
);</pre>
								</div>
								<div class="sect2" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h3 class="title">
																		<a name="manipulatingdata-criteria">
																		</a>9.3.5. 条件查询</h3>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>HQL极为强大，但是有些人希望能够动态的使用一种面向对象API创建查询，而非在他们的Java代码中嵌入字符串。对于那部分人来说，Hibernate提供了一种直观的<tt class="literal">Criteria</tt>查询API。 </p>
										<pre class="programlisting">Criteria crit = session.createCriteria(Cat.class);
crit.add( Expression.eq("color", eg.Color.BLACK) );
crit.setMaxResults(10);
List cats = crit.list();</pre>
										<p>如果你对类似于SQL的语法不是感觉很舒服的话，用这种方法开始使用Hibernate可能更容易。这种API也比HQL更可扩展。程序可以提供它们自己的<tt class="literal">Criterion</tt>接口的实现。 </p>
								</div>
								<div class="sect2" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h3 class="title">
																		<a name="manipulatingdata-nativesql">
																		</a>9.3.6. 使用本地SQL的查询</h3>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>你可以使用<tt class="literal">createSQLQuery()</tt>方法，用SQL来表达查询。你必须把SQL别名用大括号包围起来。 </p>
										<pre class="programlisting">List cats = session.createSQLQuery(
    "SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM&lt;10",
    "cat",
    Cat.class
).list();</pre>
										<pre class="programlisting">List cats = session.createSQLQuery(
    "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " +
           "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " +
    "FROM CAT {cat} WHERE ROWNUM&lt;10",
    "cat",
    Cat.class
).list()</pre>
										<p>和Hibernate查询一样，SQL查询也可以包含命名参数或者顺序参数。 </p>
								</div>
						</div>
						<div class="sect1" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h2 class="title" style="CLEAR: both">
																<a name="manipulatingdata-updating">
																</a>9.4. 更新对象</h2>
												</div>
										</div>
										<div>
										</div>
								</div>
								<div class="sect2" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h3 class="title">
																		<a name="manipulatingdata-updating-insession">
																		</a>9.4.1. 在同一Session中更新</h3>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>
												<span class="emphasis">
														<em>事务中的持久化实例</em>
												</span>（就是通过<tt class="literal">session</tt>装载、保存、创建或者查询出的对象）可以被程序操作，所做的任何修改都会在<tt class="literal">Session</tt><span class="emphasis"><em>同步（flushed）</em></span>的时候被持久化（本章后面会详细讨论）。所以最直接的更改一个对象的方法就是<tt class="literal">load()</tt>它，保持<tt class="literal">Session</tt>打开，然后直接修改即可： </p>
										<pre class="programlisting">DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) );
cat.setName("PK");
sess.flush();  // changes to cat are automatically detected and persisted</pre>
										<p>有些时候这种编程模式显得效率不高，因为它需要在同一个session中先使用SQL <tt class="literal">SELECT</tt>(来装载对象),又有一个SQL <tt class="literal">UPDATE</tt>（来把修改的状态写回）。因此，Hibernate提供了另一种方式。 </p>
								</div>
								<div class="sect2" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h3 class="title">
																		<a name="manipulatingdata-updating-detached">
																		</a>9.4.2. 更新从session脱离的对象</h3>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>很多程序需要在一个事务中获取对象，然后发送到界面层去操作，用一个新的事务来保存修改。（在高同步访问的环境中使用这种方式，经常使用附带版本的数据来保证事务独立性。）这种方法需要和上一节所描述的略微不同的编程模型。Hibernate支持这种模型，因为它提供了<tt class="literal">Session.update()</tt>方法。 </p>
										<pre class="programlisting">// in the first session
Cat cat = (Cat) firstSession.load(Cat.class, catId);
Cat potentialMate = new Cat();
firstSession.save(potentialMate);

// in a higher tier of the application
cat.setMate(potentialMate);

// later, in a new session
secondSession.update(cat);  // update cat
secondSession.update(mate); // update mate</pre>
										<p>如果拥有<tt class="literal">catId</tt>标识符的<tt class="literal">Cat</tt>在试图update它之前已经被<tt class="literal">secondSession</tt>装载了，会抛出一个异常。 </p>
										<p>对于给定的临时实例，<span class="emphasis"><em>当且仅当</em></span> 它们触及的其他临时实例需要保存的时候， 应用程序应该对它们分别各自使用<tt class="literal">update()</tt>。（自动管理生命周期的对象(lifecycle object)除外，后面会讨论到。） </p>
										<p>Hibernate用户曾经要求有一个通用的方法，可以为新建的临时实例生成标识符并保存，或者保存已经存在标识符的临时实例的改动。<tt class="literal">saveOrUpdate()</tt>方法就是用来提供这个功能的。 </p>
										<p>Hibernate通过对象的标识符的值（或version,或timestamp时间戳)来分辨这是一个“新”(未保存过的）实例，还是一个“已存在”（已经保存或者从先前的session中装载的）的实例。<tt class="literal">id</tt>映射中的<tt class="literal">unsaved-value</tt>(或<tt class="literal">&lt;version&gt;</tt>,或 <tt class="literal">&lt;timestamp&gt;</tt>)用来指定哪个值被用于表示“新”实例。 </p>
										<pre class="programlisting">&lt;id name="id" type="long" column="uid" unsaved-value="null"&gt;
    &lt;generator class="hilo"/&gt;
&lt;/id&gt;</pre>
										<p>
												<tt class="literal">unsaved-value</tt>允许的取值包括： </p>
										<div class="itemizedlist">
												<ul type="disc" compact="">
														<li>
																<p>
																		<tt class="literal">any</tt> - always save 永远保存 </p>
														</li>
														<li>
																<p>
																		<tt class="literal">none</tt> - always update 永远更新 </p>
														</li>
														<li>
																<p>
																		<tt class="literal">null</tt> - 当标识符是空的时候保存（默认情况） </p>
														</li>
														<li>
																<p>valid identifier value (合法的标识符值)- 当标识符是null或者这个给定的值时保存 </p>
														</li>
														<li>
																<p>
																		<tt class="literal">undefined</tt> - 对于<tt class="literal">version</tt> 或 <tt class="literal">timestamp</tt>来说的默认值。此时使用标识符检查。(原文: the default for <tt class="literal">version</tt> or <tt class="literal">timestamp</tt>, then identifier check is used.参见下文有进一步描述.) </p>
														</li>
												</ul>
										</div>
										<pre class="programlisting">// in the first session
Cat cat = (Cat) firstSession.load(Cat.class, catID);

// in a higher tier of the application
Cat mate = new Cat();
cat.setMate(mate);

// later, in a new session
secondSession.saveOrUpdate(cat);   // update existing state (cat has a non-null id)
secondSession.saveOrUpdate(mate);  // save the new instance (mate has a null id)</pre>
										<p>
												<tt class="literal">saveOrUpdate()</tt>的用法和语义看来对初学者来说容易造成困惑。首先，如果你还没有试图在另一个新session中使用来自原session的实例，你根本就不需要使用<tt class="literal">update()</tt>或者<tt class="literal">saveOrUpdate()</tt>方法。有一些程序完全不需要使用这些方法。 </p>
										<p>通常，<tt class="literal">update()</tt>或<tt class="literal">saveorUpdate()</tt>方法在下列情形下使用： </p>
										<div class="itemizedlist">
												<ul type="disc" compact="">
														<li>
																<p>程序在前面的session中装载了对象 </p>
														</li>
														<li>
																<p>对象被传递到UI（界面）层 </p>
														</li>
														<li>
																<p>对该对象进行了一些修改 </p>
														</li>
														<li>
																<p>对象被传递回业务层 </p>
														</li>
														<li>
																<p>应用程序在第二个session中调用<tt class="literal">update()</tt>保存修改 </p>
														</li>
												</ul>
										</div>
										<p>
												<tt class="literal">saveOrUpdate()</tt>完成了如下工作： </p>
										<div class="itemizedlist">
												<ul type="disc" compact="">
														<li>
																<p>如果对象已经在这个session中持久化过了，什么都不用做 </p>
														</li>
														<li>
																<p>如果对象没有标识值，调用<tt class="literal">save()</tt>来保存它 </p>
														</li>
														<li>
																<p>如果对象的标识值与<tt class="literal">unsaved-value</tt>中的条件匹配，调用<tt class="literal">save()</tt>来保存它 </p>
														</li>
														<li>
																<p>如果对象使用了版本(<tt class="literal">version</tt>或<tt class="literal">timestamp</tt>),那么除非设置<tt class="literal">unsaved-value="undefined"</tt>,版本检查会发生在标识符检查之前. </p>
														</li>
														<li>
																<p>如果这个session中有另外一个对象具有同样的标识符，抛出一个异常 </p>
														</li>
												</ul>
										</div>
								</div>
								<div class="sect2" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h3 class="title">
																		<a name="manipulatingdata-update-lock">
																		</a>9.4.3. 把与Session脱离的对象重新绑定</h3>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>
												<tt class="literal">lock()</tt>方法是用来让应用程序把一个未修改的对象重新关联到新session的方法。 </p>
										<pre class="programlisting">//just reassociate: 直接重新关联
sess.lock(fritz, LockMode.NONE);
//do a version check, then reassociate:  进行版本检查后关联
sess.lock(izi, LockMode.READ);
//do a version check, using SELECT ... FOR UPDATE, then reassociate: 使用SELECT ... FOR UPDATE进行版本检查后关联
sess.lock(pk, LockMode.UPGRADE);</pre>
								</div>
						</div>
						<div class="sect1" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h2 class="title" style="CLEAR: both">
																<a name="manipulatingdata-deleting">
																</a>9.5. 删除持久化对象</h2>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>使用<tt class="literal">Session.delete()</tt>会把对象的状态从数据库中移除。当然，你的应用程序可能仍然持有一个指向它的引用。所以，最好这样理解：<tt class="literal">delete()</tt>的用途是把一个持久化实例变成临时实例。 </p>
								<pre class="programlisting">sess.delete(cat);</pre>
								<p>你可以通过传递给<tt class="literal">delete()</tt>一个Hibernate 查询字符串来一次性删除很多对象。 </p>
								<p>你现在可以用你喜欢的任何顺序删除对象，不用担心外键约束冲突。当然，如果你搞错了顺序，还是有可能引发在外键字段定义的<tt class="literal">NOT NULL</tt>约束冲突。 </p>
						</div>
						<div class="sect1" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h2 class="title" style="CLEAR: both">
																<a name="manipulatingdata-flushing">
																</a>9.6. 同步（Flush）</h2>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>每件隔一段时间，<tt class="literal">Session</tt>会执行一些必需的SQL语句来把内存中的对象和JDBC连接中的状态进行同步更新。这个过程被称为<span class="emphasis"><em>同步(flush)</em></span>，默认会在下面的时间点执行： </p>
								<div class="itemizedlist">
										<ul type="disc" compact="">
												<li>
														<p>在某些<tt class="literal">find()</tt>或者<tt class="literal">iterate()</tt>调用的时候 </p>
												</li>
												<li>
														<p>在<tt class="literal">net.sf.hibernate.Transaction.commit()</tt>的时候 </p>
												</li>
												<li>
														<p>在<tt class="literal">Session.flush()</tt>的时候 </p>
												</li>
										</ul>
								</div>
								<p>涉及的SQL语句会按照下面的顺序安排： </p>
								<div class="orderedlist">
										<ol type="1" compact="">
												<li>
														<p>所有对实体进行插入的语句，其顺序按照对象执行<tt class="literal">Session.save()</tt>的时间顺序 </p>
												</li>
												<li>
														<p>所有对实体进行更新的语句 </p>
												</li>
												<li>
														<p>所有进行集合删除的语句 </p>
												</li>
												<li>
														<p>所有对集合元素进行删除，更新或者插入的语句 </p>
												</li>
												<li>
														<p>所有进行集合插入的语句 </p>
												</li>
												<li>
														<p>所有对实体进行删除的语句，其顺序按照对象执行<tt class="literal">Session.delete()</tt>的时间顺序 </p>
												</li>
										</ol>
								</div>
								<p>（有一个例外时，如果对象使用<tt class="literal">native</tt>方式进行 ID 生成的话，它们一执行save就会被插入。） </p>
								<p>除非你明确地发出了<tt class="literal">flush()</tt>指令，关于Session<span class="emphasis"><em>合时</em></span>会执行这些JDBC调用是完全无法保证的，只能保证它们执行的前后顺序。当然，Hibernate保证，<tt class="literal">Session.find(..)</tt>绝对不会返回已经失效的数据，也不会返回错误数据。 </p>
								<p>也可以改变默认的设置，来让同步发生的不那么频繁。<tt class="literal">FlushMode</tt>类定义了三种不同的方式。大部分情况下，它们只由当你在处理“只读”的事务时才会使用，可能会得到一些（不是那么明显的）性能提高。 </p>
								<pre class="programlisting">sess = sf.openSession();
Transaction tx = sess.beginTransaction();
sess.setFlushMode(FlushMode.COMMIT); //allow queries to return stale state
Cat izi = (Cat) sess.load(Cat.class, id);
izi.setName(iznizi);
// execute some queries....
sess.find("from Cat as cat left outer join cat.kittens kitten");
//change to izi is not flushed!
...
tx.commit(); //flush occurs</pre>
						</div>
						<div class="sect1" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h2 class="title" style="CLEAR: both">
																<a name="manipulatingdata-endingsession">
																</a>9.7. 结束一个Session</h2>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>结束一个session包括四个独立的步骤： </p>
								<div class="itemizedlist">
										<ul type="disc" compact="">
												<li>
														<p>清洗session </p>
												</li>
												<li>
														<p>提交事务 </p>
												</li>
												<li>
														<p>关闭session </p>
												</li>
												<li>
														<p>处理异常 </p>
												</li>
										</ul>
								</div>
								<div class="sect2" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h3 class="title">
																		<a name="manipulatingdata-endingsession-flushing">
																		</a>9.7.1. 同步(Flush) Session</h3>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>如果你正在使用<tt class="literal">Transaction</tt>API，你就不用担心这个步骤。在事务提交的时候，隐含就会包括这一步。否则，你应该调用<tt class="literal">Session.flush()</tt>来确保你所有的修改都与数据库同步。 </p>
								</div>
								<div class="sect2" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h3 class="title">
																		<a name="manipulatingdata-endingsession-commit">
																		</a>9.7.2. 提交数据库事务</h3>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>如果你正在使用Hibernate 的<tt class="literal">Transaction</tt> API,代码类似这样： </p>
										<pre class="programlisting">tx.commit(); // flush the Session and commit the transaction</pre>
										<p>如果你自行管理JDBC事务，你应该手工对JDBC 连接执行<tt class="literal">commit()</tt>。 </p>
										<pre class="programlisting">sess.flush();
sess.connection().commit();  // not necessary for JTA datasource</pre>
										<p>如果你决定<span class="emphasis"><em>不</em></span>提交你的更改： </p>
										<pre class="programlisting">tx.rollback();  // rollback the transaction</pre>
										<p>或者: </p>
										<pre class="programlisting">// not necessary for JTA datasource, important otherwise
sess.connection().rollback();</pre>
										<p>如果你回滚了事务,你应该立即关闭和取消当前session,确保Hibernate内部状态的完整性。 </p>
								</div>
								<div class="sect2" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h3 class="title">
																		<a name="manipulatingdata-endingsession-close">
																		</a>9.7.3. 关闭Session</h3>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>调用<tt class="literal">Session.close()</tt>就标志这个session进入了尾声。<tt class="literal">close()</tt>主要的含义就是与这个session相关的JDBC连接会被放弃。 </p>
										<pre class="programlisting">tx.commit();
sess.close();</pre>
										<pre class="programlisting">sess.flush();
sess.connection().commit();  // not necessary for JTA datasource
sess.close();</pre>
										<p>如果你自行管理连接，<tt class="literal">close()</tt>会返回连接的一个引用，你就可以手工把它关闭，或者返回它到连接池去。其他情况下，<tt class="literal">close()</tt>会把它返回到连接池去。 </p>
								</div>
								<div class="sect2" lang="zh-cn">
										<div class="titlepage">
												<div>
														<div>
																<h3 class="title">
																		<a name="manipulatingdata-endingsession-exceptions">
																		</a>9.7.4. 处理异常</h3>
														</div>
												</div>
												<div>
												</div>
										</div>
										<p>如果<tt class="literal">Session</tt>抛出了一个exception(包括任何<tt class="literal">SQLException</tt>),你应该立刻回滚这个事务，调用<tt class="literal">Session.close)()</tt>来取消这个<tt class="literal">Session</tt>实例。<tt class="literal">Session</tt>中的一些特定方式会确保session<span class="emphasis"><em>不会</em></span>处于一个不稳定不完整的状态。 </p>
										<p>建议采用下面的异常处理片断： </p>
										<pre class="programlisting">Session sess = factory.openSession();
Transaction tx = null;
try {
    tx = sess.beginTransaction();
    // do some work
    ...
    tx.commit();
}
catch (Exception e) {
    if (tx!=null) tx.rollback();
    throw e;
}
finally {
    sess.close();
}</pre>
										<p>如果你是手工管理JDBC事务的，用下面这段: </p>
										<pre class="programlisting">Session sess = factory.openSession();
try {
    // do some work
    ...
    sess.flush();
    sess.connection().commit();
}
catch (Exception e) {
    sess.connection().rollback();
    throw e;
}
finally {
    sess.close();
}</pre>
										<p>如果你是从JTA中获得数据源的： </p>
										<pre class="programlisting">UserTransaction ut = .... ;
Session sess = factory.openSession();
try {
    // do some work
    ...
    sess.flush();
}
catch (Exception e) {
    ut.setRollbackOnly();
    throw e;
}
finally {
    sess.close();
}</pre>
								</div>
						</div>
						<div class="sect1" lang="zh-cn">
								<div class="titlepage">
										<div>
												<div>
														<h2 class="title" style="CLEAR: both">
																<a name="manipulatingdata-graphs">
																</a>9.8. 生命周期和对象图(Lifecyles and object graphs)</h2>
												</div>
										</div>
										<div>
										</div>
								</div>
								<p>要保存或者更新一个对象关联图中所有的所有对象，你必须做到： </p>
								<div class="itemizedlist">
										<ul type="disc" compact="">
												<li>
														<p>保证每一个对象都执行<tt class="literal">save()</tt>, <tt class="literal">saveOrUpdate()</tt> 或 <tt class="literal">update()</tt>方法，或者， </p>
												</li>
												<li>
														<p>在定义关联对象的映射时，使用<tt class="literal">cascade="all"</tt>或<tt class="literal">cascade="save-update"</tt>。 </p>
												</li>
										</ul>
								</div>
								<p>类似的，要删除一个关系图中的所有对象，必须： </p>
								<div class="itemizedlist">
								</div>
						</div>
				</div>
		</div>
<img src ="http://www.cnitblog.com/forrest/aggbug/16230.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2006-08-31 18:38 <a href="http://www.cnitblog.com/forrest/articles/16230.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第 6 章 集合类(Collections)映射</title><link>http://www.cnitblog.com/forrest/articles/16228.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Thu, 31 Aug 2006 10:36:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/articles/16228.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/16228.html</wfw:comment><comments>http://www.cnitblog.com/forrest/articles/16228.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/16228.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/16228.html</trackback:ping><description><![CDATA[
		<div class="navheader">
				<table width="100%" summary="Navigation header">
						<tbody>
								<tr>
										<th align="middle" colspan="3">第 6 章 集合类(Collections)映射</th>
								</tr>
								<tr>
										<td align="left" width="20%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/mapping.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<th align="middle" width="60%"> </th>
										<td align="right" width="20%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/components.html"><font color="#002c99">下一页</font></a></td>
								</tr>
						</tbody>
				</table>
				<font color="#002c99">
						<hr />
				</font>
		</div>
		<div class="chapter" lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h2 class="title">
												<a name="collections">
												</a>第 6 章 集合类(Collections)映射</h2>
								</div>
						</div>
						<div>
						</div>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="collections-persistent">
														</a>6.1. 持久化集合类(Persistent Collections)</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>
								<a name="collections-persistent-translate-comment">
								</a>(译者注：在阅读本章的时候，以后整个手册的阅读过程中，我们都会面临一个名词方面的问题，那就是“集合”。"Collections"和"Set"在中文里对应都被翻译为“集合”，但是他们的含义很不一样。Collections是一个超集，Set是其中的一种。大部分情况下，本译稿中泛指的未加英文注明的“集合”，都应当理解为“Collections”。在有些二者同时出现，可能造成混淆的地方，我们用“集合类”来特指“Collecions”,“集合(Set)”来指"Set"，一般都会在后面的括号中给出英文。希望大家在阅读时联系上下文理解，不要造成误解。 与此同时，“元素”一词对应的英文“element”，也有两个不同的含义。其一为集合的元素，是内存中的一个变量；另一含义则是XML文档中的一个标签所代表的元素。也请注意区别。 本章中,特别是后半部分是需要反复阅读才能理解清楚的。如果遇到任何疑问,请记住,英文版本的reference是惟一标准的参考资料。) </p>
						<p>这部分不包含大量的Java代码例子。我们假定你已经了解如何使用Java自身的集合类框架(Java's collections framework)。 其实如果是这样, 这里就真的没有什么东西需要学习了... 用一句话来做个总结,你就用你已经掌握的知识来使用它们吧，不用为了适应Hibernate而作出改变. </p>
						<p>Hibernate可以持久化以下java集合的实例, 包括<tt class="literal">java.util.Map</tt>, <tt class="literal">java.util.Set</tt>, <tt class="literal">java.util.SortedMap</tt>, <tt class="literal">java.util.SortedSet</tt>, <tt class="literal">java.util.List</tt>, 和任何持久实体或值的数组。类型为<tt class="literal">java.util.Collection</tt>或者<tt class="literal">java.util.List</tt>的属性还可以使用"bag"语义来持久。 </p>
						<p>警告：用于持久化的集合，除了集合接口外，不能保留任何实现这些接口的类所附加的语义(例如:<tt class="literal">LinkedHashSet</tt>带来的迭代顺序)。所有的持久化集合，实际上都各自按照 <tt class="literal">HashMap</tt>, <tt class="literal">HashSet</tt>, <tt class="literal">TreeMap</tt>, <tt class="literal">TreeSet</tt> 和 <tt class="literal">ArrayList</tt> 的语义直接工作。更深入地说，对于一个包含集合的属性来说，必须把Java类型定义为接口（也就是<tt class="literal">Map</tt>, <tt class="literal">Set</tt> 或者<tt class="literal">List</tt>等），而绝不能是<tt class="literal">HashMap</tt>, <tt class="literal">TreeSet</tt> 或者 <tt class="literal">ArrayList</tt>。存在这个限制的原因是，在你不知道的时候，Hibernate暗中把你的<tt class="literal">Map</tt>, <tt class="literal">Set</tt> 和 <tt class="literal">List</tt> 的实例替换成了它自己的关于<tt class="literal">Map</tt>, <tt class="literal">Set</tt> 或者 <tt class="literal">List</tt> 的实现。（所以在你的程序中,谨慎使用<tt class="literal">==</tt>操作符。）(译者说明: 为了提高性能等方面的原因,在Hibernate中实现了几乎所有的Java集合的接口 。) </p>
						<pre class="programlisting">Cat cat = new DomesticCat();
Cat kitten = new DomesticCat();
....
Set kittens = new HashSet();
kittens.add(kitten);
cat.setKittens(kittens);
session.save(cat);
kittens = cat.getKittens(); //Okay, kittens collection is a Set
(HashSet) cat.getKittens(); //Error!</pre>
						<p>集合遵从对值类型的通常规则：不能共享引用, 与其包含的实体共存亡。由于存在底层的关联模型，集合不支持空值语义；并且hibernate不会区分一个null的集合引用和一个不存在元素的空集合。 </p>
						<p>集合类在被一个持久化对象引用的时候，会自动持久化，当不再被引用时将会自动删除。如果一个集合被贝从一个持久化对象传递到另一个，它的元素可讷讷个会从一个表转移到另一个表。你应该不需要对此特别关心。就如同你使用普通的Java集合类一样使用Hibernate的集合类，但是你需要确信使用前你理解了双向关联的语义（后面会讨论）。 </p>
						<p>集合实例在数据库中根据指向对应实体的外键而得到区别。这个外键被称为<span class="emphasis"><em>集合的关键字</em></span>。在Hibernate配置文件中使用<tt class="literal">&lt;key&gt;</tt> 元素来映射这个集合的关键字。 </p>
						<p>集合可以包含几乎所有的其他Hibernate类型, 包括所有的基本类型, 自定义类型,实体类型和组件。有一条重要的定义：在集合中的对象可以通过“传值”语义（完全依赖于集合自身）操作，也可以是一个指向其他实体的引用，拥有自己的生命周期。集合不能包含其他集合。这些被包含的元素的类型被称为<span class="emphasis"><em>集合元素类型</em></span>。集合的元素在Hibernate中被映射为<tt class="literal">&lt;element&gt;</tt>, <tt class="literal">&lt;composite-element&gt;</tt>, <tt class="literal">&lt;one-to-many&gt;</tt>, <tt class="literal">&lt;many-to-many&gt;</tt> 或者 <tt class="literal">&lt;many-to-any&gt;</tt>。前两种用传值语义操作元素，另外三种则映射实体关联。 </p>
						<p>除了<tt class="literal">Set</tt>和<tt class="literal">Bag</tt>之外的所有集合类型都有一个<span class="emphasis"><em>索引(index)</em></span>字段,这个字段映射到一个数组或者<tt class="literal">List</tt>的索引或者<tt class="literal">Map</tt>的key。Map的索引的类型可以是任何基本类型, 实体类型或者甚至是一个组合类型(但不能是一个集合类型)。数组和list的索引肯定是整型,<tt class="literal">integer</tt>。在Hibernate配置文件中使用 <tt class="literal">&lt;index&gt;</tt>, <tt class="literal">&lt;index-many-to-many&gt;</tt>, <tt class="literal">&lt;composite-index&gt;</tt> 或者 <tt class="literal">&lt;index-many-to-any&gt;</tt>等元素来映射索引。 </p>
						<p>集合类可以产生相当多种类的映射，涵盖了很多通常的关系模型。我们建议你练习使用schema生成工具, 以便对如何把不同的映射定义转换为数据库表有一个感性认识。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="collections-mapping">
														</a>6.2. 映射集合（Mapping a Collection）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>在Hibernate配置文件中使用<tt class="literal">&lt;set&gt;</tt>, <tt class="literal">&lt;list&gt;</tt>, <tt class="literal">&lt;map&gt;</tt>, <tt class="literal">&lt;bag&gt;</tt>, <tt class="literal">&lt;array&gt;</tt> 和 <tt class="literal">&lt;primitive-array&gt;</tt>等元素来定义集合,而<tt class="literal">&lt;map&gt;</tt>是最典型的一个。 </p>
						<div class="programlistingco">
								<pre class="programlisting">&lt;map
    name="propertyName"                                         <span class="co">(1)</span>
    table="table_name"                                          <span class="co">(2)</span>
    schema="schema_name"                                        <span class="co">(3)</span>
    lazy="true|false"                                           <span class="co">(4)</span>
    inverse="true|false"                                        <span class="co">(5)</span>
    cascade="all|none|save-update|delete|all-delete-orphan"     <span class="co">(6)</span>
    sort="unsorted|natural|comparatorClass"                     <span class="co">(7)</span>
    order-by="column_name asc|desc"                             <span class="co">(8)</span>
    where="arbitrary sql where condition"                       <span class="co">(9)</span>
    outer-join="true|false|auto"                                <span class="co">(10)</span>
    batch-size="N"                                              <span class="co">(11)</span>
    access="field|property|ClassName"                           <span class="co">(12)</span>
&gt;

    &lt;key .... /&gt;
    &lt;index .... /&gt;
    &lt;element .... /&gt;
&lt;/map&gt;</pre>
								<div class="calloutlist">
										<table summary="Callout list" border="0">
												<tbody>
														<tr>
																<td valign="top" align="left" width="5%">(1)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">name</tt> 集合属性的名称 </p>
																</td>
														</tr>
														<tr>
																<td valign="top" align="left" width="5%">(2)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">table</tt> （可选——默认为属性的名称）这个集合表的名称(不能在一对多的关联关系中使用) </p>
																</td>
														</tr>
														<tr>
																<td valign="top" align="left" width="5%">(3)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">schema</tt> (可选) 表的schema的名称, 他将覆盖在根元素中定义的schema </p>
																</td>
														</tr>
														<tr>
																<td valign="top" align="left" width="5%">(4)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">lazy</tt> (可选——默认为<tt class="literal">false</tt>) lazy(可选--默认为false) 允许延迟加载（lazy initialization ）(不能在数组中使用) </p>
																</td>
														</tr>
														<tr>
																<td valign="top" align="left" width="5%">(5)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">inverse</tt> (可选——默认为<tt class="literal">false</tt>) 标记这个集合作为双向关联关系中的方向一端。 </p>
																</td>
														</tr>
														<tr>
																<td valign="top" align="left" width="5%">(6)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">cascade</tt> (可选——默认为<tt class="literal">none</tt>) 让操作级联到子实体 </p>
																</td>
														</tr>
														<tr>
																<td valign="top" align="left" width="5%">(7)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">sort</tt>(可选)指定集合的排序顺序, 其可以为自然的(<tt class="literal">natural</tt>)或者给定一个用来比较的类。 </p>
																</td>
														</tr>
														<tr>
																<td valign="top" align="left" width="5%">(8)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">order-by</tt> (可选, 仅用于jdk1.4) 指定表的字段(一个或几个)再加上asc或者desc(可选), 定义Map,Set和Bag的迭代顺序 </p>
																</td>
														</tr>
														<tr>
																<td valign="top" align="left" width="5%">(9)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">where</tt> (可选) 指定任意的SQL where条件, 该条件将在重新载入或者删除这个集合时使用(当集合中的数据仅仅是所有可用数据的一个子集时这个条件非常有用) </p>
																</td>
														</tr>
														<tr>
																<td valign="top" align="left" width="5%">(10)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">outer-join</tt>(可选)指定这个集合,只要可能,应该通过外连接(outer join)取得。在每一个SQL语句中, 只能有一个集合可以被通过外连接抓取(译者注: 这里提到的SQL语句是取得集合所属类的数据的Select语句) </p>
																</td>
														</tr>
														<tr>
																<td valign="top" align="left" width="5%">(11)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">batch-size</tt> (可选, 默认为<tt class="literal">1</tt>) 指定通过延迟加载取得集合实例的批处理块大小（"batch size"）。 </p>
																</td>
														</tr>
														<tr>
																<td valign="top" align="left" width="5%">(12)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">access</tt>(可选-默认为属性property):Hibernate取得属性值时使用的策略 </p>
																</td>
														</tr>
												</tbody>
										</table>
								</div>
						</div>
						<p>建立<tt class="literal">列表(List)</tt>和<tt class="literal">数组(Array)</tt>需要一个单独表字段用来保存列表(List)或数组(Array)的索引(<tt class="literal">foo[i]</tt>中的<tt class="literal">i</tt>)。如果你的关系模型中没有一个索引字段, 例如:如果你处理的是老式的遗留数据, 你可以用无序的<tt class="literal">Set</tt>来替代。这会让那些以为<tt class="literal">List</tt>应该是访问无序集合的比较方便的方法的人感到气馁。Hibernate集合严格遵守Set,List和Map接口中包涵的自然语义。 <tt class="literal">List</tt>元素不能正确的自发对他们自己进行排序！ </p>
						<p>在另一方面, 那些准备使用<tt class="literal">List</tt>来模拟<span class="emphasis"><em>bag</em></span>的语义的人有一个合法的委屈(a legitimate grievance)。bag是一个无序,没有索引的集合并且可能包含多个相同的元素。在Java集合框架中没有<tt class="literal">Bag</tt>接口，但是你必须用List模拟它。Hibernate允许你映射类型为<tt class="literal">List</tt>或者<tt class="literal">Collection</tt>的属性到<tt class="literal">&lt;bag&gt;</tt>元素。注意: Bag语义事实上并不是Collection规范(contract)的一部分并且事实上它和<tt class="literal">List</tt>规范中的语义是相矛盾的。(然而，你可以对bag任意排序，在本章后面加以讨论。) </p>
						<p>注意：具有<tt class="literal">inverse="false"</tt>标记的大型Hibernate bag效率是相当低的，应该尽量避免。Hibernate无法创建,删除和更新它的单个记录, 因为他们没有关键字来识别单个记录。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="collections-ofvalues">
														</a>6.3. 值集合和多对多关联(Collections of Values and Many-To-Many Associations)</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>任何值集合和实体集合如果被映射为多对多关联(Java集合中的语义)就需要一个集合表。这个表中包含外键字段,元素字段还可能有索引字段。 </p>
						<p>使用<tt class="literal">&lt;key&gt;</tt>元素来申明从集合表到其拥有者类的表(from the collection table to the table of the owning class)的外键关键字。 </p>
						<div class="programlistingco">
								<pre class="programlisting">&lt;key column="column_name"/&gt;</pre>
								<div class="calloutlist">
										<table summary="Callout list" border="0">
												<tbody>
														<tr>
																<td valign="top" align="left" width="5%">(1)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">column</tt>(必需):外键字段的名称 </p>
																</td>
														</tr>
												</tbody>
										</table>
								</div>
						</div>
						<p>对于类似与map和list的带索引的集合, 我们需要一个<tt class="literal">&lt;index&gt;</tt>元素。对于list来说, 这个字段包含从零开始的连续整数。如果你要处理遗留的老式数据，请确保你的index真的是从0开始计数的。对于map来说,这个字段可以包含任意Hibernate类型的值。 </p>
						<div class="programlistingco">
								<pre class="programlisting">&lt;index
        column="column_name"                <span class="co">(1)</span>
        type="typename"                     <span class="co">(2)</span>
/&gt;</pre>
								<div class="calloutlist">
										<table summary="Callout list" border="0">
												<tbody>
														<tr>
																<td valign="top" align="left" width="5%">(1)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">column</tt>(必需):保存集合索引值的字段名。 </p>
																</td>
														</tr>
														<tr>
																<td valign="top" align="left" width="5%">(2)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">type</tt> (可选,默认为整型<tt class="literal">integer</tt>):集合索引的类型。 </p>
																</td>
														</tr>
												</tbody>
										</table>
								</div>
						</div>
						<p>还有另外一个选择,map可以是实体类型的对象。在这里我们使用<tt class="literal">&lt;index-many-to-many&gt;</tt>元素。 </p>
						<div class="programlistingco">
								<pre class="programlisting">&lt;index-many-to-many
        column="column_name"                <span class="co">(1)</span>
        class="ClassName"                   <span class="co">(2)</span>
/&gt;</pre>
								<div class="calloutlist">
										<table summary="Callout list" border="0">
												<tbody>
														<tr>
																<td valign="top" align="left" width="5%">(1)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">column</tt>(必需):集合索引值中外键字段的名称 </p>
																</td>
														</tr>
														<tr>
																<td valign="top" align="left" width="5%">(2)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">class</tt> (required):(必需):集合的索引使用的实体类。 </p>
																</td>
														</tr>
												</tbody>
										</table>
								</div>
						</div>
						<p>对于一个值集合, 我们使用<tt class="literal">&lt;element&gt;</tt>标签。 </p>
						<div class="programlistingco">
								<pre class="programlisting">&lt;element
        column="column_name"                <span class="co">(1)</span>
        type="typename"                     <span class="co">(2)</span>
/&gt;</pre>
								<div class="calloutlist">
										<table summary="Callout list" border="0">
												<tbody>
														<tr>
																<td valign="top" align="left" width="5%">(1)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">column</tt>(必需):保存集合元素值的字段名。 </p>
																</td>
														</tr>
														<tr>
																<td valign="top" align="left" width="5%">(2)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">type</tt> (必需):集合元素的类型 </p>
																</td>
														</tr>
												</tbody>
										</table>
								</div>
						</div>
						<p>一个拥有自己表的实体集合对应于<span class="emphasis"><em>多对多(many-to-many)关联</em></span>关系概念。多对多关联是针对Java集合的最自然映射关联关系，但通常并不是最好的关系模型。 </p>
						<div class="programlistingco">
								<pre class="programlisting">&lt;many-to-many
        column="column_name"                               <span class="co">(1)</span>
        class="ClassName"                                  <span class="co">(2)</span>
        outer-join="true|false|auto"                       <span class="co">(3)</span>
/&gt;</pre>
								<div class="calloutlist">
										<table summary="Callout list" border="0">
												<tbody>
														<tr>
																<td valign="top" align="left" width="5%">(1)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">column</tt>(必需): 这个元素的外键关键字段名 </p>
																</td>
														</tr>
														<tr>
																<td valign="top" align="left" width="5%">(2)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">class</tt> (必需): 关联类的名称 </p>
																</td>
														</tr>
														<tr>
																<td valign="top" align="left" width="5%">(3)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">outer-join</tt> (可选 - 默认为<tt class="literal">auto</tt>): 在Hibernate系统参数中<tt class="literal">hibernate.use_outer_join</tt>被打开的情况下,该参数用来允许使用outer join来载入此集合的数据。 </p>
																</td>
														</tr>
												</tbody>
										</table>
								</div>
						</div>
						<p>例子：首先, 一组字符串： </p>
						<pre class="programlisting">&lt;set name="names" table="NAMES"&gt;
    &lt;key column="GROUPID"/&gt;
    &lt;element column="NAME" type="string"/&gt;
&lt;/set&gt;</pre>
						<p>包含一组整数的bag(还设置了<tt class="literal">order-by</tt>参数指定了迭代的顺序)： </p>
						<pre class="programlisting">&lt;bag name="sizes" table="SIZES" order-by="SIZE ASC"&gt;
    &lt;key column="OWNER"/&gt;
    &lt;element column="SIZE" type="integer"/&gt;
&lt;/bag&gt;</pre>
						<p>一个实体数组,在这个案例中是一个多对多的关联(注意这里的实体是自动管理生命周期的对象（lifecycle objects）,<tt class="literal">cascade="all"</tt>): </p>
						<pre class="programlisting">&lt;array name="foos" table="BAR_FOOS" cascade="all"&gt;
    &lt;key column="BAR_ID"/&gt;
    &lt;index column="I"/&gt;
    &lt;many-to-many column="FOO_ID" class="org.hibernate.Foo"/&gt;
&lt;/array&gt;</pre>
						<p>一个map,通过字符串的索引来指明日期： </p>
						<pre class="programlisting">&lt;map name="holidays" table="holidays" schema="dbo" order-by="hol_name asc"&gt;
    &lt;key column="id"/&gt;
    &lt;index column="hol_name" type="string"/&gt;
    &lt;element column="hol_date" type="date"/&gt;
&lt;/map&gt;</pre>
						<p>一个组件的列表：（下一章讨论） </p>
						<pre class="programlisting">&lt;list name="carComponents" table="car_components"&gt;
    &lt;key column="car_id"/&gt;
    &lt;index column="posn"/&gt;
    &lt;composite-element class="org.hibernate.car.CarComponent"&gt;
            &lt;property name="price" type="float"/&gt;
            &lt;property name="type" type="org.hibernate.car.ComponentType"/&gt;
            &lt;property name="serialNumber" column="serial_no" type="string"/&gt;
    &lt;/composite-element&gt;
&lt;/list&gt;</pre>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="collections-onetomany">
														</a>6.4. 一对多关联（One-To-Many Associations）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>
								<span class="emphasis">
										<em>一对多关联</em>
								</span>
								<span class="emphasis">
										<em>直接</em>
								</span>连接两个类对应的表,而没有中间集合表。(这实现了一个<span class="emphasis"><em>一对多</em></span>的关系模型)(译者注:这有别与多对多的关联需要一张中间表)。 这个关系模型失去了一些Java集合的语义: </p>
						<div class="itemizedlist">
								<ul type="disc" compact="">
										<li>
												<p>map,set或list中不能包含null值 </p>
										</li>
										<li>
												<p>一个被包含的实体的实例只能被包含在一个集合的实例中 </p>
										</li>
										<li>
												<p>一个被包含的实体的实例只能对应于集合索引的一个值中 </p>
										</li>
								</ul>
						</div>
						<p>一个从<tt class="literal">Foo</tt>到<tt class="literal">Bar</tt>的关联需要额外的关键字字段,可能还有一个索引字段指向这个被包含的实体类,<tt class="literal">Bar</tt>所对应的表。这些字段在映射时使用前面提到的<tt class="literal">&lt;key&gt;</tt>和<tt class="literal">&lt;index&gt;</tt>元素。 </p>
						<p>
								<tt class="literal">&lt;one-to-many&gt;</tt>标记指明了一个一对多的关联。 </p>
						<div class="programlistingco">
								<pre class="programlisting">&lt;one-to-many class="ClassName"/&gt;</pre>
								<div class="calloutlist">
										<table summary="Callout list" border="0">
												<tbody>
														<tr>
																<td valign="top" align="left" width="5%">(1)</td>
																<td valign="top" align="left">
																		<p>
																				<tt class="literal">class</tt>(必须):被关联类的名称。 </p>
																</td>
														</tr>
												</tbody>
										</table>
								</div>
						</div>
						<p>例子 </p>
						<pre class="programlisting">&lt;set name="bars"&gt;
    &lt;key column="foo_id"/&gt;
    &lt;one-to-many class="org.hibernate.Bar"/&gt;
&lt;/set&gt;</pre>
						<p>注意:<tt class="literal">&lt;one-to-many&gt;</tt>元素不需要定义任何字段。 也不需要指定表名。 </p>
						<p>
								<span class="emphasis">
										<em>重要提示</em>
								</span>:如果<tt class="literal">一对多</tt>关联中的<tt class="literal">&lt;key&gt;</tt>字段定义成<tt class="literal">NOT NULL</tt>,那么当创建和更新关联关系时Hibernate可能引起约束违例。为了预防这个问题,<span class="emphasis"><em>你必须使用双向关联</em></span>，并且在“多”这一端（Set或者是bag)指明<tt class="literal">inverse="true"</tt>。参阅本章后面关于双向关联的讨论。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="collections-lazy">
														</a>6.5. 延迟初始化(延迟加载)（Lazy Initialization）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>
								<a name="collections-lazy-translate-comment-zh-cn">
								</a>(译者注: 本翻译稿中，对Lazy Initiazation和Eager fetch中的lazy,eager采取意译的方式，分别翻译为延迟初始化和预先抓取。lazt initiazation就是指直到第一次调用时才加载。） </p>
						<p>集合(不包括数组)是可以延迟初始化的,意思是仅仅当应用程序需要访问时，才载入他们的值。对于使用者来说，初始化是透明的, 因此应用程序通常不需要关心这个(事实上,透明的延迟加载也就是为什么Hibernate需要自己的集合实现的主要原因)。但是, 如何应用程序试图执行以下程序: </p>
						<pre class="programlisting">s = sessions.openSession();
User u = (User) s.find("from User u where u.name=?", userName, Hibernate.STRING).get(0);
Map permissions = u.getPermissions();
s.connection().commit();
s.close();

Integer accessLevel = (Integer) permissions.get("accounts");  // Error!</pre>
						<p>这个错误可能令你感到意外。因为在这个<tt class="literal">Session</tt>被提交(commit)之前, permissions没有被初始化,那么这个集合将永远不能载入他的数据了。 解决方法是把读取集合数据的语句提到Session被提交之前。(然而，还有一种更先进的方法来解决这个问题。) </p>
						<p>另外一种选择是不使用延迟初始化集合。既然延迟初始化可能引起上面这样错误,默认是不使用延迟初始化的。但是, 为了效率的原因, 我们希望对绝大多数集合(特别是实体集合)使用延迟初始化。 </p>
						<p>延迟初始化集合时发生的例外被封装在<tt class="literal">LazyInitializationException</tt>中。 </p>
						<p>使用可选的 <tt class="literal">lazy</tt> 属性来定义延迟初始化集合： </p>
						<pre class="programlisting">&lt;set name="names" table="NAMES" lazy="true"&gt;
    &lt;key column="group_id"/&gt;
    &lt;element column="NAME" type="string"/&gt;
&lt;/set&gt;</pre>
						<p>在一些应用程序的体系结构中,特别是使用hibernate访问数据的结构, 代码可能会用在不用的应用层中, 可能没有办法保证当一个集合在初始化的时候, session仍然打开着。 这里有两个基本方法来解决这个问题： </p>
						<div class="itemizedlist">
								<ul type="disc">
										<li>
												<p>在基于Web的应用程序中, 一个servlet过滤器可以用来在用户请求的完成之前来关闭<tt class="literal">Session</tt>。当然,这个地方(关闭session)严重依赖于你的应用程序结构中例外处理的正确性。在请求返回给用户之前关闭<tt class="literal">Session</tt>和结束事务是非常重要的,即使是在构建视图(译者注: 返回给用户的HTML页面)的时候发生了例外,也必须确保这一点。考虑到这一点，servlet过滤器可以保证能够操作这个<tt class="literal">Session</tt>。我们推荐使用一个<tt class="literal">ThreadLocal</tt>变量来保存当前的<tt class="literal">Session</tt>。（参阅第一章，<a title="1.4.&amp;nbsp;与猫同乐" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/quickstart.html#quickstart-playingwithcats"><font color="#002c99">第 1.4 节 “与猫同乐”</font></a>,有一个参考实现。） </p>
										</li>
										<li>
												<p>在一个有单独的商业层的应用程序中, 商业逻辑必须在返回之前“准备好”Web层所需要的所有集合。这就是说商业逻辑层应该装载好所有的数据，把一个用例所需要的所有数据都初始化好，传递给表现/web层。通常, 应用程序为每个Web层需要的集合调用<tt class="literal">Hibernate.initialize()</tt>(必须在Session被关闭之前调用)或者通过使用Hibernate 查询，用<tt class="literal">FETCH</tt>子句来明确获取到整个集合。 </p>
										</li>
										<li>
												<p>You may also attach a previously loaded object to a new <tt class="literal">Session</tt> with <tt class="literal">update()</tt> or <tt class="literal">lock()</tt> before accessing unitialized collections (or other proxies). Hibernate can not do this automatically, as it would introduce ad hoc transaction semantics! 你也可以把先前装载的对象附加到一个新的<tt class="literal">Session</tt>去，需要在访问未初始化的集合类（或其他代理）前使用<tt class="literal">update()</tt> 或 <tt class="literal">lock()</tt>。Hibernate不能自动做这件事，这回带来特别的事务语义！ </p>
										</li>
								</ul>
						</div>
						<p>你可以使用Hibernate Session API中的<tt class="literal">filter()</tt> 方法来在初始化之前得到集合的大小： </p>
						<pre class="programlisting">( (Integer) s.filter( collection, "select count(*)" ).get(0) ).intValue()</pre>
						<p>
								<tt class="literal">filter()</tt> 或者 <tt class="literal">createFilter()</tt>同样被用于有效的重新载入一个集合的子集而不需要载入整个集合。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="collections-sorted">
														</a>6.6. 集合排序（Sorted Collections）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>Hibernate支持实现<tt class="literal">java.util.SortedMap</tt>和<tt class="literal">java.util.SortedSet</tt>的集合。你必须在映射文件中指定一个比较器： </p>
						<pre class="programlisting">&lt;set name="aliases" table="person_aliases" sort="natural"&gt;
    &lt;key column="person"/&gt;
    &lt;element column="name" type="string"/&gt;
&lt;/set&gt;

&lt;map name="holidays" sort="my.custom.HolidayComparator" lazy="true"&gt;
    &lt;key column="year_id"/&gt;
    &lt;index column="hol_name" type="string"/&gt;
    &lt;element column="hol_date" type="date"/&gt;
&lt;/map&gt;</pre>
						<p>
								<tt class="literal">sort</tt>属性中允许的值包括<tt class="literal">unsorted</tt>,<tt class="literal">natural</tt>和某个实现了<tt class="literal">java.util.Comparator</tt>的类的名称。 </p>
						<p>分类集合的行为事实上象<tt class="literal">java.util.TreeSet</tt>或者<tt class="literal">java.util.TreeMap</tt>。 </p>
						<p>如果你希望数据库自己对集合元素排序，可以利用<tt class="literal">set</tt>,<tt class="literal">bag</tt>或者<tt class="literal">map</tt>映射中的<tt class="literal">order-by</tt>属性。这个解决方案只能在jdk1.4或者更高的jdk版本中才可以实现(通过LinkedHashSet或者 LinkedHashMap实现)。 它是在SQL查询中完成排序，而不是在内存中。 </p>
						<pre class="programlisting">&lt;set name="aliases" table="person_aliases" order-by="name asc"&gt;
    &lt;key column="person"/&gt;
    &lt;element column="name" type="string"/&gt;
&lt;/set&gt;

&lt;map name="holidays" order-by="hol_date, hol_name" lazy="true"&gt;
    &lt;key column="year_id"/&gt;
    &lt;index column="hol_name" type="string"/&gt;
    &lt;element column="hol_date" type="date"/&gt;
&lt;/map&gt;</pre>
						<p>注意: 这个<tt class="literal">order-by</tt>属性的值是一个SQL排序子句而不是HQL的！ </p>
						<p>关联还可以在运行时使用<tt class="literal">filter()</tt>根据任意的条件来排序。 </p>
						<pre class="programlisting">sortedUsers = s.filter( group.getUsers(), "order by this.name" );</pre>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="collections-idbag">
														</a>6.7. <tt class="literal">使用&lt;idbag&gt;</tt></h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>如果你完全信奉我们对于“联合主键（composite keys）是个坏东西”，和“实体应该使用（无机的）自己生成的代用标识符（surrogate keys）”的观点，也许你会感到有一些奇怪，我们目前为止展示的多对多关联和值集合都是映射成为带有联合主键的表的！现在，这一点非常值得争辩；看上去一个单纯的关联表并不能从代用标识符中获得什么好处（虽然使用组合值的集合<span class="emphasis"><em>可能</em></span>会获得一点好处）。不过，Hibernate提供了一个（一点点试验性质的）功能，让你把多对多关联和值集合应得到一个使用代用标识符的表去。 </p>
						<p>
								<tt class="literal">&lt;idbag&gt;</tt> 属性让你使用bag语义来映射一个<tt class="literal">List</tt> (或<tt class="literal">Collection</tt>)。 </p>
						<pre class="programlisting">&lt;idbag name="lovers" table="LOVERS" lazy="true"&gt;
    &lt;collection-id column="ID" type="long"&gt;
        &lt;generator class="hilo"/&gt;
    &lt;/collection-id&gt;
    &lt;key column="PERSON1"/&gt;
    &lt;many-to-many column="PERSON2" class="eg.Person" outer-join="true"/&gt;
&lt;/idbag&gt;</pre>
						<p>你可以理解，<tt class="literal">&lt;idbag&gt;</tt>人工的id生成器，就好像是实体类一样！集合的每一行都有一个不同的人造关键字。但是，Hibernate没有提供任何机制来让你取得某个特定行的人造关键字。 </p>
						<p>注意<tt class="literal">&lt;idbag&gt;</tt>的更新性能要比普通的<tt class="literal">&lt;bag&gt;</tt>高得多！Hibernate可以有效的定位到不同的行，分别进行更新或删除工作，就如同处理一个list, map或者set一样。 </p>
						<p>在目前的实现中，还不支持使用<tt class="literal">identity</tt>标识符生成器策略来生成<tt class="literal">&lt;idbag&gt;</tt>集合的标识符。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="collections-bidirectional">
														</a>6.8. 双向关联（Bidirectional Associations）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>
								<span class="emphasis">
										<em>双向关联</em>
								</span>允许通过关联的任一端访问另外一端。在Hibernate中, 支持两种类型的双向关联: </p>
						<div class="variablelist">
								<dl>
										<dt>
												<span class="term">一对多（one-to-many）</span>
										</dt>
										<dd>
												<p>Set或者bag值在一端, 单独值(非集合)在另外一端 </p>
										</dd>
										<dt>
												<span class="term">多对多（many-to-many）</span>
										</dt>
										<dd>
												<p>两端都是set或bag值 </p>
										</dd>
								</dl>
						</div>
						<p>
						</p>
						<p>请注意Hibernate不支持带有索引的集合(list,map或者array)作为"多"的那一端的双向one-to-many关联,你必须使用集合或者bag映射. </p>
						<p>要建立一个双向的多对多关联，只需要映射两个many-to-many关联到同一个数据库表中，并再定义其中的一端为<span class="emphasis"><em>inverse</em></span>(使用哪一端要根据你的选择)。这里有一个从一个类关联到<span class="emphasis"><em>他自身</em></span>的many-to-many的双向关联的例子(每一个category都可以有很多items,每一个items可以属于很多categories)： </p>
						<pre class="programlisting">&lt;class name="org.hibernate.auction.Category"&gt;
    &lt;id name="id" column="ID"/&gt;
    ...
    &lt;bag name="items" table="CATEGORY_ITEM" lazy="true"&gt;
        &lt;key column="CATEGORY_ID"/&gt;
        &lt;many-to-many class="org.hibernate.auction.Item" column="ITEM_ID"/&gt;
    &lt;/bag&gt;
&lt;/class&gt;

&lt;class name="org.hibernate.auction.Item"&gt;
    &lt;id name="id" column="ID"/&gt;
    ...

    &lt;!-- inverse end --&gt;
    &lt;bag name="categories" table="CATEGORY_ITEM" inverse="true" lazy="true"&gt;
        &lt;key column="ITEM_ID"/&gt;
        &lt;many-to-many class="org.hibernate.auction.Category" column="CATEGORY_ID"/&gt;
    &lt;/bag&gt;
&lt;/class&gt;</pre>
						<p>如果只对关联的反向端进行了改变，这个改变<span class="emphasis"><em>不会</em></span>被持久化。 这表示Hibernate为每个双向关联在内存中存在两次表现,一个从A连接到B,另一个从B连接到A。如果你回想一下Java对象模型，我们是如何在Java中创建多对多关系的，这可以让你更容易理解： </p>
						<pre class="programlisting">category.getItems().add(item);          // The category now "knows" about the relationship
item.getCategories().add(category);     // The item now "knows" about the relationship

session.update(item);                     // No effect, nothing will be saved!
session.update(category);                 // The relationship will be saved</pre>
						<p>非反向端用于把内存中的表示保存到数据库中。如果两端都进行了改编，我们会进行多余的INSERT/UPDATE,甚至可能得到外键冲突！这一点对双向的一对多关联也是一样的。 </p>
						<p>要建立一个一对多的双向关联，你可以通过把一个一对多关联，作为一个多对一关联映射到到同一张表的字段上，并且在"多"的那一端定义<tt class="literal">inverse="true"</tt>。 （原文： You may map a bidirectional one-to-many association by mapping a one-to-many association to the same table column(s) as a many-to-one association and declaring the many-valued end <tt class="literal">inverse="true"</tt>.） </p>
						<pre class="programlisting">&lt;class name="eg.Parent"&gt;
    &lt;id name="id" column="id"/&gt;
    ....
    &lt;set name="children" inverse="true" lazy="true"&gt;
        &lt;key column="parent_id"/&gt;
        &lt;one-to-many class="eg.Child"/&gt;
    &lt;/set&gt;
&lt;/class&gt;

&lt;class name="eg.Child"&gt;
    &lt;id name="id" column="id"/&gt;
    ....
    &lt;many-to-one name="parent" class="eg.Parent" column="parent_id"/&gt;
&lt;/class&gt;</pre>
						<p>在“一”这一端定义<tt class="literal">inverse="true"</tt>不会影响级联操作，二者是不同的概念！ </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="collections-ternary">
														</a>6.9. 三重关联（Ternary Associations）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>这里有两种可能的途径来映射一个三重关联。其中一个是使用组合元素(下面将讨论).另外一个是使用一个map，并且带有关联作为其索引： </p>
						<pre class="programlisting">&lt;map name="contracts" lazy="true"&gt;
    &lt;key column="employer_id"/&gt;
    &lt;index-many-to-many column="employee_id" class="Employee"/&gt;
    &lt;one-to-many class="Contract"/&gt;
&lt;/map&gt;</pre>
						<pre class="programlisting">&lt;map name="connections" lazy="true"&gt;
    &lt;key column="node1_id"/&gt;
    &lt;index-many-to-many column="node2_id" class="Node"/&gt;
    &lt;many-to-many column="connection_id" class="Connection"/&gt;
&lt;/map&gt;</pre>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="collections-heterogeneous">
														</a>6.10. 异类关联(Heterogeneous Associations)</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>
								<tt class="literal">&lt;many-to-any&gt;</tt>和<tt class="literal">&lt;index-many-to-any&gt;</tt>元素提供真正的异类关联。这些元素和<tt class="literal">&lt;any&gt;</tt>元素工作方式是同样的,他们都应该很少用到。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="collections-example">
														</a>6.11. 集合例子（Collection example）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>在前面的几个章节的确非常令人迷惑。 因此让我们来看一个例子。这个类： </p>
						<pre class="programlisting">package eg;
import java.util.Set;

public class Parent {
    private long id;
    private Set children;

    public long getId() { return id; }
    private void setId(long id) { this.id=id; }

    private Set getChildren() { return children; }
    private void setChildren(Set children) { this.children=children; }

    ....
    ....
}</pre>
						<p>这个类有一个<tt class="literal">eg.Child</tt>的实例集合。如果每一个子实例至多有一个父实例, 那么最自然的映射是一个one-to-many的关联关系： </p>
						<pre class="programlisting">&lt;hibernate-mapping&gt;

    &lt;class name="eg.Parent"&gt;
        &lt;id name="id"&gt;
            &lt;generator class="sequence"/&gt;
        &lt;/id&gt;
        &lt;set name="children" lazy="true"&gt;
            &lt;key column="parent_id"/&gt;
            &lt;one-to-many class="eg.Child"/&gt;
        &lt;/set&gt;
    &lt;/class&gt;

    &lt;class name="eg.Child"&gt;
        &lt;id name="id"&gt;
            &lt;generator class="sequence"/&gt;
        &lt;/id&gt;
        &lt;property name="name"/&gt;
    &lt;/class&gt;

&lt;/hibernate-mapping&gt;</pre>
						<p>在以下的表定义中反应了这个映射关系： </p>
						<pre class="programlisting">create table parent ( id bigint not null primary key )
create table child ( id bigint not null primary key, name varchar(255), parent_id bigint )
alter table child add constraint childfk0 (parent_id) references parent</pre>
						<p>如果父亲是<span class="emphasis"><em>必须</em></span>的, 那么就可以使用双向one-to-many的关联了： </p>
						<pre class="programlisting">&lt;hibernate-mapping&gt;

    &lt;class name="eg.Parent"&gt;
        &lt;id name="id"&gt;
            &lt;generator class="sequence"/&gt;
        &lt;/id&gt;
        &lt;set name="children" inverse="true" lazy="true"&gt;
            &lt;key column="parent_id"/&gt;
            &lt;one-to-many class="eg.Child"/&gt;
        &lt;/set&gt;
    &lt;/class&gt;

    &lt;class name="eg.Child"&gt;
        &lt;id name="id"&gt;
            &lt;generator class="sequence"/&gt;
        &lt;/id&gt;
        &lt;property name="name"/&gt;
        &lt;many-to-one name="parent" class="eg.Parent" column="parent_id" not-null="true"/&gt;
    &lt;/class&gt;

&lt;/hibernate-mapping&gt;</pre>
						<p>请注意<tt class="literal">NOT NULL</tt>的约束: </p>
						<pre class="programlisting">create table parent ( id bigint not null primary key )
create table child ( id bigint not null
                     primary key,
                     name varchar(255),
                     parent_id bigint not null )
alter table child add constraint childfk0 (parent_id) references parent</pre>
						<p>另外一方面,如果一个子实例可能有多个父实例, 那么就应该使用many-to-many关联： </p>
						<pre class="programlisting">&lt;hibernate-mapping&gt;

    &lt;class name="eg.Parent"&gt;
        &lt;id name="id"&gt;
            &lt;generator class="sequence"/&gt;
        &lt;/id&gt;
        &lt;set name="children" lazy="true" table="childset"&gt;
            &lt;key column="parent_id"/&gt;
            &lt;many-to-many class="eg.Child" column="child_id"/&gt;
        &lt;/set&gt;
    &lt;/class&gt;

    &lt;class name="eg.Child"&gt;
        &lt;id name="id"&gt;
            &lt;generator class="sequence"/&gt;
        &lt;/id&gt;
        &lt;property name="name"/&gt;
    &lt;/class&gt;

&lt;/hibernate-mapping&gt;</pre>
						<p>表定义： </p>
						<pre class="programlisting">create table parent ( id bigint not null primary key )
create table child ( id bigint not null primary key, name varchar(255) )
create table childset ( parent_id bigint not null,
                        child_id bigint not null,
                        primary key ( parent_id, child_id ) )
alter table childset add constraint childsetfk0 (parent_id) references parent
alter table childset add constraint childsetfk1 (child_id) references child</pre>
				</div>
		</div>
		<div class="navfooter">
				<hr />
				<table width="100%" summary="Navigation footer">
						<tbody>
								<tr>
										<td align="left" width="40%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/mapping.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<td align="middle" width="20%">
												<a accesskey="u" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">上一级</font>
												</a>
										</td>
										<td align="right" width="40%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/components.html"><font color="#002c99">下一页</font></a></td>
								</tr>
								<tr>
										<td valign="top" align="left" width="40%">第 5 章 O/R Mapping基础 </td>
										<td align="middle" width="20%">
												<a accesskey="h" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">起始页</font>
												</a>
										</td>
										<td valign="top" align="right" width="40%"> 第 7 章 组件（Component）映射</td>
								</tr>
						</tbody>
				</table>
		</div>
<img src ="http://www.cnitblog.com/forrest/aggbug/16228.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2006-08-31 18:36 <a href="http://www.cnitblog.com/forrest/articles/16228.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第 7 章 组件（Component）映射</title><link>http://www.cnitblog.com/forrest/articles/16229.html</link><dc:creator>forrest</dc:creator><author>forrest</author><pubDate>Thu, 31 Aug 2006 10:36:00 GMT</pubDate><guid>http://www.cnitblog.com/forrest/articles/16229.html</guid><wfw:comment>http://www.cnitblog.com/forrest/comments/16229.html</wfw:comment><comments>http://www.cnitblog.com/forrest/articles/16229.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cnitblog.com/forrest/comments/commentRss/16229.html</wfw:commentRss><trackback:ping>http://www.cnitblog.com/forrest/services/trackbacks/16229.html</trackback:ping><description><![CDATA[
		<div class="navheader">
				<table width="100%" summary="Navigation header">
						<tbody>
								<tr>
										<th align="middle" colspan="3">第 7 章 组件（Component）映射</th>
								</tr>
								<tr>
										<td align="left" width="20%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/collections.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<th align="middle" width="60%"> </th>
										<td align="right" width="20%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/inheritance.html"><font color="#002c99">下一页</font></a></td>
								</tr>
						</tbody>
				</table>
				<font color="#002c99">
						<hr />
				</font>
		</div>
		<div class="chapter" lang="zh-cn">
				<div class="titlepage">
						<div>
								<div>
										<h2 class="title">
												<a name="components">
												</a>第 7 章 组件（Component）映射</h2>
								</div>
						</div>
						<div>
						</div>
				</div>
				<p>
						<span class="emphasis">
								<em>Component</em>
						</span>这个概念在Hibernate中几处不同的地方为了不同的目的被重复使用. </p>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="components-dependentobjects">
														</a>7.1. 依赖对象（Dependent objects）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>Component是一个被包含的对象,它作为值类型被持久化，而非一个实体。“component(组件)”这一术语指的是面向对象的合成概念（而并不是系统构架层次上的组件的概念）举个例子, 你可以对人（Person)如以下这样来建模： </p>
						<pre class="programlisting">public class Person {
    private java.util.Date birthday;
    private Name name;
    private String key;
    public String getKey() {
        return key;
    }
    private void setKey(String key) {
        this.key=key;
    }
    public java.util.Date getBirthday() {
        return birthday;
    }
    public void setBirthday(java.util.Date birthday) {
        this.birthday = birthday;
    }
    public Name getName() {
        return name;
    }
    public void setName(Name name) {
        this.name = name;
    }
    ......
    ......
}</pre>
						<pre class="programlisting">public class Name {
    char initial;
    String first;
    String last;
    public String getFirst() {
        return first;
    }
    void setFirst(String first) {
        this.first = first;
    }
    public String getLast() {
        return last;
    }
    void setLast(String last) {
        this.last = last;
    }
    public char getInitial() {
        return initial;
    }
    void setInitial(char initial) {
        this.initial = initial;
    }
}</pre>
						<p>现在,<tt class="literal">姓名(Name)</tt>是作为<tt class="literal">人(Person)</tt>的一个组成部分。需要注意的是:需要对<tt class="literal">姓名</tt> 的持久化属性定义getter和setter方法,但是不需要实现任何的接口或申明标识符字段。 </p>
						<p>以下是这个例子的Hibernate映射文件: </p>
						<pre class="programlisting">&lt;class name="eg.Person" table="person"&gt;
    &lt;id name="Key" column="pid" type="string"&gt;
        &lt;generator class="uuid.hex"/&gt;
    &lt;/id&gt;
    &lt;property name="birthday" type="date"/&gt;
    &lt;component name="Name" class="eg.Name"&gt; &lt;!-- class attribute optional --&gt;
        &lt;property name="initial"/&gt;
        &lt;property name="first"/&gt;
        &lt;property name="last"/&gt;
    &lt;/component&gt;
&lt;/class&gt;</pre>
						<p>人员(Person)表中将包括<tt class="literal">pid</tt>, <tt class="literal">birthday</tt>, <tt class="literal">initial</tt>, <tt class="literal">first</tt>和 <tt class="literal">last</tt>等字段。 </p>
						<p>就像所有的值类型一样, Component不支持共享引用。Component的值为空从语义学上来讲是<span class="emphasis"><em>专有的</em></span>。 每当 重新加载一个包含组件的对象,如果component的所有字段为空，那么将Hibernate将假定整个component为 空。对于绝大多数目的,这样假定是没有问题的。 </p>
						<p>Component的属性可以是Hibernate类型（包括Collections, many-to-one 关联， 以及其它Component 等等）。嵌套Component不应该作为特殊的应用被考虑(Nested components should not be considered an exotic usage)。 Hibernate趋向于支持设计细致(fine-grained)的对象模型。 </p>
						<p>
								<tt class="literal">&lt;component&gt;</tt> 元素还允许有 <tt class="literal">&lt;parent&gt;</tt>子元素 ，用来表明component类中的一个属性返回包含它的实体的引用。 </p>
						<pre class="programlisting">&lt;class name="eg.Person" table="person"&gt;
    &lt;id name="Key" column="pid" type="string"&gt;
        &lt;generator class="uuid.hex"/&gt;
    &lt;/id&gt;
    &lt;property name="birthday" type="date"/&gt;
    &lt;component name="Name" class="eg.Name"&gt;
        &lt;parent name="namedPerson"/&gt; &lt;!-- reference back to the Person --&gt;
        &lt;property name="initial"/&gt;
        &lt;property name="first"/&gt;
        &lt;property name="last"/&gt;
    &lt;/component&gt;
&lt;/class&gt;</pre>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="components-incollections">
														</a>7.2. 在集合中出现的依赖对象</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>Hibernate支持component的集合(例如: 一个元素是“姓名”这种类型的数组)。 你可以使用<tt class="literal">&lt;composite-element&gt;</tt>标签替代<tt class="literal">&lt;element&gt;</tt>标签来定义你的component集合。 </p>
						<pre class="programlisting">&lt;set name="someNames" table="some_names" lazy="true"&gt;
    &lt;key column="id"/&gt;
    &lt;composite-element class="eg.Name"&gt; &lt;!-- class attribute required --&gt;
        &lt;property name="initial"/&gt;
        &lt;property name="first"/&gt;
        &lt;property name="last"/&gt;
    &lt;/composite-element&gt;
&lt;/set&gt;</pre>
						<p>注意，如果你决定定义一个元素是联合元素的<tt class="literal">Set</tt>，正确地实现<tt class="literal">equals()</tt>和<tt class="literal">hashCode()</tt>是非常重要的。 </p>
						<p>组合元素可以包含component但是不能包含集合。如果你的组合元素自身包含component, 必须使用<tt class="literal">&lt;nested-composite-element&gt;</tt>标签。这是一个相当特殊的案例 - 组合元素的集合自身可以包含component。 这个时候你就应该考虑一下使用one-to-many关联是否会更恰当。 尝试对这个组合元素重新建模为一个实体－但是需要注意的是，虽然Java模型和重新建模前 是一样的，关系模型和持久性语义上仍然存在轻微的区别。 </p>
						<p>请注意如果你使用<tt class="literal">&lt;set&gt;</tt>标签,一个组合元素的映射不支持可能为空的属性. 当删除对象时, Hibernate必须使用每一个字段的来确定一条记录(在组合元素表中，没有单个的关键字段), 如果有为null的字段，这样做就不可能了。你必须作出一个选择，要么在组合元素中使用不能为空的属性， 要么选择使用<tt class="literal">&lt;list&gt;</tt>, <tt class="literal">&lt;map&gt;</tt>,<tt class="literal">&lt;bag&gt;</tt> 或者 <tt class="literal">&lt;idbag&gt;</tt>而不是 <tt class="literal">&lt;set&gt;</tt>。 </p>
						<p>组合元素有个特别的案例，是组合元素可以包含一个<tt class="literal">&lt;many-to-one&gt;</tt> 元素。类似这样的映射允许你映射一个many-to-mang关联表作为组合元素额外的字段。(A mapping like this allows you to map extra columns of a many-to-many association table to the composite element class.) 接下来的的例子是从<tt class="literal">Order</tt>到<tt class="literal">Item</tt>的一个多对多的关联关系,而 <tt class="literal">purchaseDate</tt>, <tt class="literal">price</tt> 和 <tt class="literal">quantity</tt> 是<tt class="literal">Item</tt>的关联属性。 </p>
						<pre class="programlisting">&lt;class name="eg.Order" .... &gt;
    ....
    &lt;set name="purchasedItems" table="purchase_items" lazy="true"&gt;
        &lt;key column="order_id"&gt;
        &lt;composite-element class="eg.Purchase"&gt;
            &lt;property name="purchaseDate"/&gt;
            &lt;property name="price"/&gt;
            &lt;property name="quantity"/&gt;
            &lt;many-to-one name="item" class="eg.Item"/&gt; &lt;!-- class attribute is optional --&gt;
        &lt;/composite-element&gt;
    &lt;/set&gt;
&lt;/class&gt;</pre>
						<p>即使三重或多重管理都是可能的:</p>
						<pre class="programlisting">&lt;class name="eg.Order" .... &gt;
    ....
    &lt;set name="purchasedItems" table="purchase_items" lazy="true"&gt;
        &lt;key column="order_id"&gt;
        &lt;composite-element class="eg.OrderLine"&gt;
            &lt;many-to-one name="purchaseDetails" class="eg.Purchase"/&gt;
            &lt;many-to-one name="item" class="eg.Item"/&gt;
        &lt;/composite-element&gt;
    &lt;/set&gt;
&lt;/class&gt;</pre>
						<p>在查询中，组合元素使用的语法是和关联到其他实体的语法一样的。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="components-asmapindex">
														</a>7.3. 组件作为Map的索引（Components as Map indices ）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>
								<tt class="literal">&lt;composite-index&gt;</tt>元素允许你映射一个Component类作为<tt class="literal">Map</tt>的key， 但是你必须确定你正确的在这个类中重写了<tt class="literal">hashCode()</tt> 和 <tt class="literal">equals()</tt>方法。 </p>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="components-compositeid">
														</a>7.4. 组件作为联合标识符(Components as composite identifiers)</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>你可以使用一个component作为一个实体类的标识符。 你的component类必须满足以下要求： </p>
						<div class="itemizedlist">
								<ul type="disc" compact="">
										<li>
												<p>它必须实现<tt class="literal">java.io.Serializable</tt>接口 </p>
										</li>
										<li>
												<p>它必须重新实现<tt class="literal">equals()</tt>和<tt class="literal">hashCode()</tt>方法, 始终和组合关键字在数据库中的概念保持一致 </p>
										</li>
								</ul>
						</div>
						<p>你不能使用一个<tt class="literal">IdentifierGenerator</tt>产生组合关键字。作为替代应用程序必 须分配它自己的标识符. </p>
						<p>既然联合标识符必须在对象存储之前被分配，我们就不能使用标识符的<tt class="literal">unsaved-value</tt>来把刚刚新建的实例和在先前的session保存的实例区分开来。 </p>
						<p>如果你希望使用<tt class="literal">saveOrUpdate()</tt>或者级联保存/更新(cascading save / update)，你应该实现 <tt class="literal">Interceptor.isUnsaved()</tt>。使用<tt class="literal">&lt;composite-id&gt;</tt> 标签(它和<tt class="literal">&lt;component&gt;</tt>标签有同样的属性和元素)代替<tt class="literal">&lt;id&gt;</tt>标签。 下面有个联合标识符类的定义: </p>
						<pre class="programlisting">&lt;class name="eg.Foo" table"FOOS"&gt;
    &lt;composite-id name="compId" class="eg.FooCompositeID"&gt;
        &lt;key-property name="string"/&gt;
        &lt;key-property name="short"/&gt;
        &lt;key-property name="date" column="date_" type="date"/&gt;
    &lt;/composite-id&gt;
    &lt;property name="name"/&gt;
    ....
&lt;/class&gt;</pre>
						<p>这时候,任何到<tt class="literal">FOOS</tt>的外键也同样是联合的， 在你其他类的映射文件中也必须同样定义。 一个到<tt class="literal">Foo</tt>的定义应该像以下这样: </p>
						<pre class="programlisting">&lt;many-to-one name="foo" class="eg.Foo"&gt;
&lt;!-- the "class" attribute is optional, as usual --&gt;
    &lt;column name="foo_string"/&gt;
    &lt;column name="foo_short"/&gt;
    &lt;column name="foo_date"/&gt;
&lt;/many-to-one&gt;</pre>
						<p>新的 <tt class="literal">&lt;column&gt;</tt> 标签同样被用于包含多个字段的自定义类型（This new <tt class="literal">column</tt>tag is also used by multi-column custom types）。 事实上在各个地方它都是一个可选的字段属性。要定义一个元素是<tt class="literal">Foo</tt>的集合类，要这样写: </p>
						<pre class="programlisting">&lt;set name="foos"&gt;
    &lt;key column="owner_id"/&gt;
    &lt;many-to-many class="eg.Foo"&gt;
        &lt;column name="foo_string"/&gt;
        &lt;column name="foo_short"/&gt;
        &lt;column name="foo_date"/&gt;
    &lt;/many-to-many&gt;
&lt;/set&gt;</pre>
						<p>另一方面，<tt class="literal">&lt;one-to-many&gt;</tt>元素通常不定义字段. </p>
						<p>如果 <tt class="literal">Foo</tt> 自己包含集合， 那么他们也需要使用联合外键。 </p>
						<pre class="programlisting">&lt;class name="eg.Foo"&gt;
    ....
    ....
    &lt;set name="dates" lazy="true"&gt;
        &lt;key&gt;   &lt;!-- a collection inherits the composite key type --&gt;
            &lt;column name="foo_string"/&gt;
            &lt;column name="foo_short"/&gt;
            &lt;column name="foo_date"/&gt;
        &lt;/key&gt;
        &lt;element column="foo_date" type="date"/&gt;
    &lt;/set&gt;
&lt;/class&gt;</pre>
				</div>
				<div class="sect1" lang="zh-cn">
						<div class="titlepage">
								<div>
										<div>
												<h2 class="title" style="CLEAR: both">
														<a name="components-dynamic">
														</a>7.5. 动态组件 （Dynamic components）</h2>
										</div>
								</div>
								<div>
								</div>
						</div>
						<p>你甚至可以映射<tt class="literal">Map</tt>类型的属性： </p>
						<pre class="programlisting">&lt;dynamic-component name="userAttributes"&gt;
    &lt;property name="foo" column="FOO"/&gt;
    &lt;property name="bar" column="BAR"/&gt;
    &lt;many-to-one name="baz" class="eg.Baz" column="BAZ"/&gt;
&lt;/dynamic-component&gt;</pre>
						<p>从<tt class="literal">&lt;dynamic-component&gt;</tt>映射的语义上来讲，它和<tt class="literal">&lt;component&gt;</tt>是相同的。 这种映射类型的优点在于通过修改映射文件，就可以具有在部署时检测真实属性的能力.(利用一个DOM解析器， 是有可能在运行时刻操作映射文件的。) </p>
				</div>
		</div>
		<div class="navfooter">
				<hr />
				<table width="100%" summary="Navigation footer">
						<tbody>
								<tr>
										<td align="left" width="40%">
												<a accesskey="p" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/collections.html">
														<font color="#002c99">上一页</font>
												</a> </td>
										<td align="middle" width="20%">
												<a accesskey="u" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">上一级</font>
												</a>
										</td>
										<td align="right" width="40%"> <a accesskey="n" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/inheritance.html"><font color="#002c99">下一页</font></a></td>
								</tr>
								<tr>
										<td valign="top" align="left" width="40%">第 6 章 集合类(Collections)映射 </td>
										<td align="middle" width="20%">
												<a accesskey="h" href="http://www.hibernate.org/hib_docs/reference/zh-cn/html/index.html">
														<font color="#002c99">起始页</font>
												</a>
										</td>
										<td valign="top" align="right" width="40%"> 第 8 章 继承映射(Inheritance Mappings)</td>
								</tr>
						</tbody>
				</table>
		</div>
<img src ="http://www.cnitblog.com/forrest/aggbug/16229.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cnitblog.com/forrest/" target="_blank">forrest</a> 2006-08-31 18:36 <a href="http://www.cnitblog.com/forrest/articles/16229.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>