﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-【永恒的瞬间】  -文章分类-hibernate</title><link>http://www.blogjava.net/19851985lili/category/18358.html</link><description>☜GivE mE HapPy ☞




</description><language>zh-cn</language><lastBuildDate>Tue, 15 May 2007 11:54:50 GMT</lastBuildDate><pubDate>Tue, 15 May 2007 11:54:50 GMT</pubDate><ttl>60</ttl><item><title>HIbernate体系结构</title><link>http://www.blogjava.net/19851985lili/articles/117638.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 15 May 2007 08:04:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/117638.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/117638.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/117638.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/117638.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/117638.html</trackback:ping><description><![CDATA[<div class=chapter lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title><a name=architecture></a>第&nbsp;3&nbsp;章&nbsp;体系结构(Architecture)</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=architecture-overview></a>3.1.&nbsp;概况(Overview)</h2>
</div>
</div>
<div></div>
</div>
<p>一个非常简要的Hibernate体系结构的概要图： </p>
<div class=mediaobject align=center>这个图可以看出，Hibernater使用数据库和配置信息来为应用程序提供持久化服务（以及持久的对象）。 </div>
<p>我们来更详细地看一下Hibernate运行时体系结构。由于Hibernate非常灵活，且支持数种应用方案， 所以我们这只描述一下两种极端的情况。&#8220;轻型&#8221;的体系结构方案，要求应用程序提供自己的JDBC 连接并管理自己的事务。这种方案使用了Hibernate API的最小子集： </p>
<div class=mediaobject align=center>&#8220;全面解决&#8221;的体系结构方案，将应用层从底层的JDBC/JTA API中抽象出来，而让Hibernate来处理这些细节。 </div>
<div class=mediaobject align=center>图中各个对象的定义如下： </div>
<div class=variablelist>
<dl>
<dt><span class=term>SessionFactory (<tt class=literal>org.hibernate.SessionFactory</tt>)</span>
<dd>
<p>针对单个数据库映射关系经过编译后的内存镜像，它也是线程安全的（不可变）。 它是生成<tt class=literal>Session</tt>的工厂，本身要用到<tt class=literal>ConnectionProvider</tt>。 该对象可以在进程或集群的级别上，为那些事务之间可以重用的数据提供可选的二级缓存。 </p>
<dt><span class=term>Session (<tt class=literal>org.hibernate.Session</tt>)</span>
<dd>
<p>表示应用程序与持久储存层之间交互操作的一个单线程对象，此对象生存期很短。 其隐藏了JDBC连接，也是<tt class=literal>Transaction</tt>的工厂。 其会持有一个针对持久化对象的必选（第一级）缓存，在遍历对象图或者根据持久化标识查找对象时会用到。 </p>
<dt><span class=term>持久的对象及其集合</span>
<dd>
<p>带有持久化状态的、具有业务功能的单线程对象，此对象生存期很短。 这些对象可以是普通的JavaBeans/POJO，唯一特殊的是他们正与（仅仅一个）<tt class=literal>Session</tt>相关联。 这个<tt class=literal>Session</tt>被关闭的同时，这些对象也会脱离持久化状态，可以被应用程序的任何层自由使用。 （例如，用作跟表示层打交道的数据传输对象data transfer object。） </p>
<dt><span class=term>瞬态(transient)以及脱管(detached)的对象及其集合</span>
<dd>
<p>持久类的没有与<tt class=literal>Session</tt>相关联的实例。 他们可能是在被应用程序实例化后，尚未进行持久化的对象。 也可能是因为实例化他们的<tt class=literal>Session</tt>已经被关闭而脱离持久化的对象。 </p>
<dt><span class=term>事务Transaction (<tt class=literal>org.hibernate.Transaction</tt>)</span>
<dd>
<p>（可选的）应用程序用来指定原子操作单元范围的对象，它是单线程的，生存期很短。 它通过抽象将应用从底层具体的JDBC、JTA以及CORBA事务隔离开。 某些情况下，一个<tt class=literal>Session</tt>之内可能包含多个<tt class=literal>Transaction</tt>对象。 尽管是否使用该对象是可选的，但是事务边界的开启与关闭（无论是使用底层的API还是使用<tt class=literal>Transaction</tt>对象）是必不可少的。 </p>
<dt><span class=term>ConnectionProvider (<tt class=literal>org.hibernate.connection.ConnectionProvider</tt>)</span>
<dd>
<p>（可选的）生成JDBC连接的工厂（同时也起到连接池的作用）。 它通过抽象将应用从底层的<tt class=literal>Datasource</tt>或<tt class=literal>DriverManager</tt>隔离开。 仅供开发者扩展/实现用，并不暴露给应用程序使用。 </p>
<dt><span class=term>TransactionFactory (<tt class=literal>org.hibernate.TransactionFactory</tt>)</span>
<dd>
<p>（可选的）生成<tt class=literal>Transaction</tt>对象实例的工厂。 仅供开发者扩展/实现用，并不暴露给应用程序使用。 </p>
<dt><span class=term><span class=emphasis><em>扩展接口</em></span></span>
<dd>
<p>Hibernate提供了很多可选的扩展接口，你可以通过实现它们来定制你的持久层的行为。 具体请参考API文档。 </p>
</dd></dl></div>
<p>&nbsp;</p>
<p>在一个&#8220;轻型&#8221;的体系结构中，应用程序可能绕过 <tt class=literal>Transaction</tt>/<tt class=literal>TransactionFactory</tt> 以及 <tt class=literal>ConnectionProvider</tt> 等API直接跟JTA或JDBC打交道。 </p>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=architecture-states></a>3.2.&nbsp;实例状态</h2>
</div>
</div>
<div></div>
</div>
<p>一个持久化类的实例可能处于三种不同状态中的某一种。 这三种状态的定义则与所谓的<span class=emphasis><em>持久化上下文(persistence context)</em></span>有关。 Hibernate的<tt class=literal>Session</tt>对象就是这个所谓的持久化上下文： </p>
<div class=variablelist>
<dl>
<dt><span class=term>瞬态（transient）</span>
<dd>
<p>该实例从未与任何持久化上下文关联过。它没有持久化标识（相当于主键）。 </p>
<dt><span class=term>持久(persistent)</span>
<dd>
<p>实例目前与某个持久化上下文有关联。 它拥有持久化标识（相当于主键），并且可能在数据库中有一个对应的行。 对于某一个特定的持久化上下文，Hibernate<span class=emphasis><em>保证</em></span>持久化标识与Java标识（其值代表对象在内存中的位置）等价。 </p>
<dt><span class=term>脱管(detached)</span>
<dd>
<p>实例曾经与某个持久化上下文发生过关联，不过那个上下文被关闭了， 或者这个实例是被序列化(serialize)到这个进程来的。 它拥有持久化标识，并且在数据库中可能存在一个对应的行。 对于脱管状态的实例，Hibernate不保证任何持久化标识和Java标识的关系。 </p>
</dd></dl></div>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=architecture-jmx></a>3.3.&nbsp;JMX整合</h2>
</div>
</div>
<div></div>
</div>
<p>JMX是管理Java组件(Java components)的J2EE规范。 Hibernate 可以通过一个JMX标准服务来管理。 在这个发行版本中，我们提供了一个MBean接口的实现,即 <tt class=literal>org.hibernate.jmx.HibernateService</tt>。 </p>
<p>想要看如何在JBoss应用服务器上将Hibernate部署为一个JMX服务的例子，您可以参考JBoss用户指南。 我们现在说一下在Jboss应用服务器上，使用JMX来部署Hibernate的好处： </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p><span class=emphasis><em>Session管理：</em></span> Hibernate的<tt class=literal>Session</tt>对象的生命周期可以 自动跟一个JTA事务边界绑定。这意味着你无需手工开关<tt class=literal>Session</tt>了, 这项 工作会由JBoss EJB 拦截器来完成。你再也不用担心你的代码中的事务边界了(除非你想利用Hibernate提供 的<tt class=literal>Transaction</tt> API来自己写一个便于移植的的持久层)。 你现在要通过 <tt class=literal>HibernateContext</tt>来操作<tt class=literal>Session</tt>了。 </p>
    <li>
    <p><span class=emphasis><em>HAR 部署:</em></span> 通常情况下，你会使用JBoss的服务部署描述符（在EAR或/和SAR文件中）来部署Hibernate JMX服务。 这种部署方式支持所有常见的Hibernate <tt class=literal>SessionFactory</tt>的配置选项。 不过，你需在部署描述符中，列出你所有的映射文件的名字。如果你使用HAR部署方式, JBoss 会自动探测出你的HAR文件中所有的映射文件。 </p>
    </li>
</ul>
</div>
<p>这些选项更多的描述，请参考JBoss 应用程序用户指南。 </p>
<p>将Hibernate以部署为JMX服务的另一个好处，是可以查看Hibernate的运行时统计信息。参看 <a title="4.4.6.&nbsp;&#10;                Hibernate的统计(statistics)机制&#10;            " href="file:///E:/_DataBank/_JavaHelp/Hibernatehelp/session-configuration.html#configuration-optional-statistics" tppabs="http://www.hibernate.org/hib_docs/v3/reference/zh-cn/html/session-configuration.html#configuration-optional-statistics">第&nbsp;4.4.6&nbsp;节 &#8220; Hibernate的统计(statistics)机制 &#8221;</a>. </p>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=architecture-jca></a>3.4.&nbsp;对JCA的支持</h2>
</div>
</div>
<div></div>
</div>
<p>Hibernate也可以被配置为一个JCA连接器（JCA connector）。更多信息请参看网站。 请注意，Hibernate对JCA的支持，仍处于实验性质。 </p>
</div>
</div>
<div class=chapter lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title><a name=persistent-classes></a>第&nbsp;5&nbsp;章&nbsp;持久化类(Persistent Classes)</h2>
</div>
</div>
<div></div>
</div>
<p>在应用程序中，用来实现业务问题实体的（如，在电子商务应用程序中的Customer和Order） 类就是持久化类。不能认为所有的持久化类的实例都是持久的状态——一个实例的状态也可能 是瞬时的或脱管的。 </p>
<p>如果这些持久化类遵循一些简单的规则，Hibernate能够工作得最好，这些规则被称作， 简单传统Java对象(POJO:Plain Old Java Object)编程模型。但是这些规则没有一个是必需的。 实际上，Hibernate3对于你的持久化类几乎不做任何设想。你可以用其他的方法来表达领域模型： 比如，使用<tt class=literal>Map</tt>实例的树型结构。 </p>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=persistent-classes-pojo></a>5.1.&nbsp;一个简单的POJO例子</h2>
</div>
</div>
<div></div>
</div>
<p>大多数Java程序需要用一个持久化类来表示猫科动物。 </p>
<pre class=programlisting>package eg;
import java.util.Set;
import java.util.Date;
public class Cat {
private Long id; // identifier
private Date birthdate;
private Color color;
private char sex;
private float weight;
private int litterId;
private Cat mother;
private Set kittens = new HashSet();
private void setId(Long id) {
this.id=id;
}
public Long getId() {
return id;
}
void setBirthdate(Date date) {
birthdate = date;
}
public Date getBirthdate() {
return birthdate;
}
void setWeight(float weight) {
this.weight = weight;
}
public float getWeight() {
return weight;
}
public Color getColor() {
return color;
}
void setColor(Color color) {
this.color = color;
}
void setSex(char sex) {
this.sex=sex;
}
public char getSex() {
return sex;
}
void setLitterId(int id) {
this.litterId = id;
}
public int getLitterId() {
return litterId;
}
void setMother(Cat mother) {
this.mother = mother;
}
public Cat getMother() {
return mother;
}
void setKittens(Set kittens) {
this.kittens = kittens;
}
public Set getKittens() {
return kittens;
}
// addKitten not needed by Hibernate
public void addKitten(Cat kitten) {
kitten.setMother(this);
kitten.setLitterId( kittens.size() );
kittens.add(kitten);
}
}</pre>
<p>这里要遵循四条主要的规则： </p>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=persistent-classes-pojo-accessors></a>5.1.1.&nbsp;为持久化字段声明访问器(accessors)和是否可变的标志(mutators)</h3>
</div>
</div>
<div></div>
</div>
<p><tt class=literal>Cat</tt>为它的所有持久化字段声明了访问方法。很多其他ORM工具直接对 实例变量进行持久化。我们相信从持久化机制中分离这种实现细节要好得多。 Hibernate持久化JavaBeans风格的属性，认可如下形式的方法名： <tt class=literal>getFoo</tt>, <tt class=literal>isFoo</tt> 和 <tt class=literal>setFoo</tt>。 如果需要，你总是可以切换特定的属性的指示字段的访问方法。 </p>
<p>属性<span class=emphasis><em>不需要</em></span>要声明为public的。Hibernate默认使用 <tt class=literal>protected</tt>或<tt class=literal>private</tt>的get/set方法对， 对属性进行持久化。 </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=persistent-classes-pojo-constructor></a>5.1.2.&nbsp;实现一个默认的（即无参数的）构造方法（constructor）</h3>
</div>
</div>
<div></div>
</div>
<p><tt class=literal>Cat</tt>有一个无参数的构造方法。所有的持久化类都必须有一个 默认的构造方法（可以不是public的），这样的话Hibernate就可以使用 <tt class=literal>Constructor.newInstance()</tt>来实例化它们。 我们建议，在Hibernate中，为了运行期代理的生成，构造方法至少是 <span class=emphasis><em>包(package)</em></span>内可见的。 </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=persistent-classes-pojo-identifier></a>5.1.3.&nbsp;提供一个标识属性（identifier property）（可选） </h3>
</div>
</div>
<div></div>
</div>
<p><tt class=literal>Cat</tt>有一个属性叫做<tt class=literal>id</tt>。这个属性映射数据库表的主 键字段。这个属性可以叫任何名字，其类型可以是任何的原始类型、原始类型的包装类型、 <tt class=literal>java.lang.String</tt> 或者是 <tt class=literal>java.util.Date</tt>。 （如果你的老式数据库表有联合主键，你甚至可以用一个用户自定义的类，该类拥有这些类型 的属性。参见后面的关于联合标识符的章节。） </p>
<p>标识符属性是可选的。可以不用管它，让Hibernate内部来追踪对象的识别。 不推荐使用这个属性。 </p>
<p>实际上，一些功能只对那些声明了标识符属性的类起作用： </p>
<div class=itemizedlist>
<ul type=disc compact>
    <li>
    <p>托管对象的传播性重新（和session）关联（级联更新或级联合并） ——参阅 <a title="11.11.&nbsp;传播性持久化(transitive persistence)" href="file:///E:/_DataBank/_JavaHelp/Hibernatehelp/objectstate.html#objectstate-transitive" tppabs="http://www.hibernate.org/hib_docs/v3/reference/zh-cn/html/objectstate.html#objectstate-transitive">第&nbsp;11.11&nbsp;节 &#8220;传播性持久化(transitive persistence)&#8221;</a> </p>
    <li>
    <p><tt class=literal>Session.saveOrUpdate()</tt> </p>
    <li>
    <p><tt class=literal>Session.merge()</tt> </p>
    </li>
</ul>
</div>
<p>我们建议你对持久化类声明命名一致的标识属性。我们还建议你使用一 个可以为空（也就是说，不是原始类型）的类型。 </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=persistent-classes-pojo-final></a>5.1.4.&nbsp;使用非final的类 (可选)</h3>
</div>
</div>
<div></div>
</div>
<p><span class=emphasis><em>代理（proxies）</em></span>是Hibernate的一个重要的功能，它依赖的条件是，持久 化类或者是非final的，或者是实现了一个所有方法都声明为public的接口。 </p>
<p>你可以用Hibernate持久化一个没有实现任何接口的<tt class=literal>final</tt>类，但是你 不能使用代理来延迟关联加载，这会限制你进行性能优化的选择。 </p>
<p>你也应该避免在非final类中声明 <tt class=literal>public final</tt>的方法。如果你想使用一 个有<tt class=literal>public final</tt>方法的类，你必须通过设置<tt class=literal>lazy="false"</tt> 来明确的禁用代理。 </p>
</div>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=persistent-classes-inheritance></a>5.2.&nbsp;实现继承（Inheritance）</h2>
</div>
</div>
<div></div>
</div>
<p>子类也必须遵守第一条和第二条规则。它从超类<tt class=literal>Cat</tt>继承了标识属性。 </p>
<pre class=programlisting>package eg;
public class DomesticCat extends Cat {
private String name;
public String getName() {
return name;
}
protected void setName(String name) {
this.name=name;
}
}</pre>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=persistent-classes-equalshashcode></a>5.3.&nbsp;实现<tt class=literal>equals()</tt>和<tt class=literal>hashCode()</tt></h2>
</div>
</div>
<div></div>
</div>
<p>如果你有如下需求，你必须重载 <tt class=literal>equals()</tt> 和 <tt class=literal>hashCode()</tt>方法： </p>
<div class=itemizedlist>
<ul type=disc compact>
    <li>
    <p>想把持久类的实例放入<tt class=literal>Set</tt>中（当表示多值关联时，推荐这么做） </p>
    <li>
    <p>想重用脱管实例 </p>
    </li>
</ul>
</div>
<p>Hibernate保证，持久化标识（数据库的行）和仅在特定会话范围内的Java标识是等值的。因此，一旦 我们混合了从不同会话中获取的实例，如果我们希望<tt class=literal>Set</tt>有明确的语义，我们必 须实现<tt class=literal>equals()</tt> 和<tt class=literal>hashCode()</tt>。 </p>
<p>实现<tt class=literal>equals()</tt>/<tt class=literal>hashCode()</tt>最显而易见的方法是比较两个对象 标识符的值。如果值相同，则两个对象对应于数据库的同一行，因此它们是相等的（如果都被添加到 <tt class=literal>Set</tt>，则在<tt class=literal>Set</tt>中只有一个元素）。不幸的是，对生成的标识不能 使用这种方法。Hibernate仅对那些持久化对象赋标识值，一个新创建的实例将不会有任何标识值。此外， 如果一个实例没有被保存(unsaved)，并且在一个<tt class=literal>Set</tt>中，保存它将会给这个对象 赋一个标识值。如果<tt class=literal>equals()</tt> 和 <tt class=literal>hashCode()</tt>是基于标识值 实现的，则其哈希码将会改变，违反<tt class=literal>Set</tt>的契约。建议去Hibernate的站点看关于这个 问题的全部讨论。注意，这不是一个Hibernate问题，而是一般的Java对象标识和相等的语义问题。 </p>
<p>我们建议使用<span class=emphasis><em>业务键值相等(Business key equality)</em></span>来实现<tt class=literal>equals()</tt> 和 <tt class=literal>hashCode()</tt>。业务键值相等的意思是，<tt class=literal>equals()</tt>方法 仅仅比较来自业务键的属性，一个业务键将标识在真实世界里（一个<span class=emphasis><em>天生的</em></span>候选键） 的实例。 </p>
<pre class=programlisting>public class Cat {
...
public boolean equals(Object other) {
if (this == other) return true;
if ( !(other instanceof Cat) ) return false;
final Cat cat = (Cat) other;
if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
if ( !cat.getMother().equals( getMother() ) ) return false;
return true;
}
public int hashCode() {
int result;
result = getMother().hashCode();
result = 29 * result + getLitterId();
return result;
}
}</pre>
<p>注意，业务键不必是象数据库的主键那样是固定不变的（参见<a title="12.1.3.&nbsp;关注对象标识(Considering object identity)" href="file:///E:/_DataBank/_JavaHelp/Hibernatehelp/transactions.html#transactions-basics-identity" tppabs="http://www.hibernate.org/hib_docs/v3/reference/zh-cn/html/transactions.html#transactions-basics-identity">第&nbsp;12.1.3&nbsp;节 &#8220;关注对象标识(Considering object identity)&#8221;</a>）。 对业务键而言，不可变或唯一的属性是好的候选。 </p>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=persistent-classes-dynamicmodels></a>5.4.&nbsp;动态模型(Dynamic models)</h2>
</div>
</div>
<div></div>
</div>
<p><span class=emphasis><em>注意，以下特性在当前是基于实验考虑的，可能会在将来改变。</em></span> </p>
<p>运行期的持久化实体没有必要象POJO类或JavaBean对象一样表示。Hibernate也支持动态模型 （在运行期使用<tt class=literal>Map</tt>的<tt class=literal>Map</tt>）和象DOM4J的树模型那 样的实体表示。使用这种方法，你不用写持久化类，只写映射文件就行了。 </p>
<p>Hibernate默认工作在普通POJO模式。你可以使用配置选项<tt class=literal>default_entity_mode</tt>， 对特定的<tt class=literal>SessionFactory</tt>，设置一个默认的实体表示模式。 （参见<a title="表&nbsp;4.3.&nbsp;&#10;                Hibernate配置属性&#10;            " href="file:///E:/_DataBank/_JavaHelp/Hibernatehelp/session-configuration.html#configuration-optional-properties" tppabs="http://www.hibernate.org/hib_docs/v3/reference/zh-cn/html/session-configuration.html#configuration-optional-properties">表&nbsp;4.3 &#8220; Hibernate配置属性 &#8221;</a>。） </p>
<p>下面是用<tt class=literal>Map</tt>来表示的例子。首先，在映射文件中，要声明 <tt class=literal>entity-name</tt>来代替（或外加）一个类名。 </p>
<pre class=programlisting>&lt;hibernate-mapping&gt;
&lt;class entity-name="Customer"&gt;
&lt;id name="id"
type="long"
column="ID"&gt;
&lt;generator class="sequence"/&gt;
&lt;/id&gt;
&lt;property name="name"
column="NAME"
type="string"/&gt;
&lt;property name="address"
column="ADDRESS"
type="string"/&gt;
&lt;many-to-one name="organization"
column="ORGANIZATION_ID"
class="Organization"/&gt;
&lt;bag name="orders"
inverse="true"
lazy="false"
cascade="all"&gt;
&lt;key column="CUSTOMER_ID"/&gt;
&lt;one-to-many class="Order"/&gt;
&lt;/bag&gt;
&lt;/class&gt;
&lt;/hibernate-mapping&gt;</pre>
<p>注意，虽然是用目标类名来声明关联的，但是关联的目标类型除了是POJO之外，也可以 是一个动态的实体。 </p>
<p>在使用<tt class=literal>dynamic-map</tt>为<tt class=literal>SessionFactory</tt> 设置了默认的实体模式之后，可以在运行期使用<tt class=literal>Map</tt>的 <tt class=literal>Map</tt>。 </p>
<pre class=programlisting>Session s = openSession();
Transaction tx = s.beginTransaction();
Session s = openSession();
// Create a customer
Map david = new HashMap();
david.put("name", "David");
// Create an organization
Map foobar = new HashMap();
foobar.put("name", "Foobar Inc.");
// Link both
david.put("organization", foobar);
// Save both
s.save("Customer", david);
s.save("Organization", foobar);
tx.commit();
s.close();</pre>
<p>动态映射的好处是，使原型在不需要实体类实现的情况下，快速转变时间。然而，你无法进行 编译期的类型检查，并可能由此会处理很多的运行期异常。幸亏有了Hibernate映射，它使得数 据库的schema能容易的规格化和合理化，并允许稍后添加正确的领域模型的最新实现。 </p>
<p>实体表示模式也能在每个<tt class=literal>Session</tt>的基础上设置： </p>
<pre class=programlisting>Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
// Create a customer
Map david = new HashMap();
david.put("name", "David");
dynamicSession.save("Customer", david);
...
dynamicSession.flush();
dynamicSession.close()
...
// Continue on pojoSession
</pre>
<p>请注意，用<tt class=literal>EntityMode</tt>调用<tt class=literal>getSession()</tt>是在 <tt class=literal>Session</tt>的API中，而不是<tt class=literal>SessionFactory</tt>。 这样，新的<tt class=literal>Session</tt>共享底层的JDBC连接，事务，和其他的上下文信 息。这意味着，你不需要在第二个<tt class=literal>Session</tt>中调用 <tt class=literal>flush()</tt>和<tt class=literal>close()</tt>，同样的，把事务和连接的处理 交给原来的工作单元。 </p>
<p>关于XML表示能力的更多信息可以在<a title=第&nbsp;19&nbsp;章&nbsp;XML映射 href="file:///E:/_DataBank/_JavaHelp/Hibernatehelp/xml.html" tppabs="http://www.hibernate.org/hib_docs/v3/reference/zh-cn/html/xml.html">第&nbsp;19&nbsp;章 <em>XML映射</em></a>中找到。 </p>
</div>
<p>TODO：在property和proxy的包里，用户扩展文件框架。 </p>
</div>
<img src ="http://www.blogjava.net/19851985lili/aggbug/117638.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-05-15 16:04 <a href="http://www.blogjava.net/19851985lili/articles/117638.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HIbernate工具箱指南</title><link>http://www.blogjava.net/19851985lili/articles/117636.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 15 May 2007 08:01:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/117636.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/117636.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/117636.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/117636.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/117636.html</trackback:ping><description><![CDATA[<div class=chapter lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title><a name=toolsetguide></a>第&nbsp;21&nbsp;章&nbsp;工具箱指南</h2>
</div>
</div>
<div></div>
</div>
<p>可以通过一系列Eclipse插件、命令行工具和Ant任务来进行与Hibernate关联的转换。 </p>
<p>除了Ant任务外，当前的<span class=emphasis><em>Hibernate Tools</em></span>也包含了Eclipse IDE的插件，用于与现存数据库的逆向工程。 </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p><span class=emphasis><em>Mapping Editor:</em></span> Hibernate XML映射文件的编辑器，支持自动完成和语法高亮。它也支持对类名和属性/字段名的语义自动完成，比通常的XML编辑器方便得多。 </p>
    <li>
    <p><span class=emphasis><em>Console:</em></span> Console是Eclipse的一个新视图。除了对你的console配置的树状概览，你还可以获得对你持久化类及其关联的交互式视图。Console允许你对数据库执行HQL查询，并直接在Eclipse中浏览结果。 </p>
    <li>
    <p><span class=emphasis><em>Development Wizards:</em></span> 在Hibernate Eclipse tools中还提供了几个向导；你可以用向导快速生成Hibernate 配置文件（cfg.xml），你甚至还可以同现存的数据库schema中反向工程出POJO源代码与Hibernate 映射文件。反向工程支持可定制的模版。 </p>
    <li>
    <p><span class=emphasis><em>Ant Tasks:</em></span> </p>
    </li>
</ul>
</div>
<p>要得到更多信息，请查阅 <span class=emphasis><em>Hibernate Tools</em></span> 包及其文档。 </p>
<p>同时，Hibernate主发行包还附带了一个集成的工具（它甚至可以在Hibernate&#8220;内部&#8221;快速运行）<span class=emphasis><em>SchemaExport</em></span> ，也就是 <tt class=literal>hbm2ddl</tt>。 </p>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=toolsetguide-s1></a>21.1.&nbsp;Schema自动生成（Automatic schema generation）</h2>
</div>
</div>
<div></div>
</div>
<p>可以从你的映射文件使用一个Hibernate工具生成DDL。 生成的schema包含有对实体和集合类表的完整性引用约束（主键和外键）。涉及到的标示符生成器所需的表和sequence也会同时生成。 </p>
<p>在使用这个工具的时候，你<span class=emphasis><em>必须</em></span> 通过<tt class=literal>hibernate.dialet</tt>属性指定一个SQL<tt class=literal>方言(Dialet)</tt>，因为DDL是与供应商高度相关的。 </p>
<p>首先，要定制你的映射文件，来改善生成的schema。 </p>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=toolsetguide-s1-2></a>21.1.1.&nbsp;对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><strong>表&nbsp;21.1.&nbsp;Summary</strong></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>21.1.2.&nbsp;运行该工具</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>org.hibernate.tool.hbm2ddl.SchemaExport</tt> <span class=emphasis><em>options mapping_files</em></span> </p>
<div class=table><a name=d0e14194></a>
<p class=title><strong>表&nbsp;21.2.&nbsp;<tt class=literal>SchemaExport</tt>命令行选项</strong></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>21.1.3.&nbsp;属性(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>
    <p>在<tt class=literal>hibernate.properties</tt>文件中</p>
    <li>
    <p>位于一个其它名字的properties文件中,然后用 <tt class=literal>--properties</tt>参数指定</p>
    </li>
</ul>
</div>
<p>所需的参数包括: </p>
<div class=table><a name=d0e14292></a>
<p class=title><strong>表&nbsp;21.3.&nbsp;SchemaExport 连接属性</strong></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>21.1.4.&nbsp;使用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="org.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>21.1.5.&nbsp;对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>org.hibernate.tool.hbm2ddl.SchemaUpdate</tt> <span class=emphasis><em>options mapping_files</em></span> </p>
<div class=table><a name=d0e14369></a>
<p class=title><strong>表&nbsp;21.4.&nbsp;<tt class=literal>SchemaUpdate</tt>命令行选项</strong></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>21.1.6.&nbsp;用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="org.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>
<img src ="http://www.blogjava.net/19851985lili/aggbug/117636.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-05-15 16:01 <a href="http://www.blogjava.net/19851985lili/articles/117636.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HIbernate提升性能 </title><link>http://www.blogjava.net/19851985lili/articles/117633.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 15 May 2007 07:58:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/117633.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/117633.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/117633.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/117633.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/117633.html</trackback:ping><description><![CDATA[<div class=titlepage>
<div>
<div>
<h2 class=title><a name=performance></a>第&nbsp;20&nbsp;章&nbsp;提升性能 </h2>
</div>
</div>
<div></div>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=performance-fetching></a>20.1.&nbsp; 抓取策略(Fetching strategies) </h2>
</div>
</div>
<div></div>
</div>
<p><span class=emphasis><em>抓取策略（fetching strategy）</em></span> 是指：当应用程序需要在（Hibernate实体对象图的）关联关系间进行导航的时候， Hibernate如何获取关联对象的策略。抓取策略可以在O/R映射的元数据中声明，也可以在特定的HQL 或<tt class=literal>条件查询（Criteria Query）</tt>中重载声明。 </p>
<p>Hibernate3 定义了如下几种抓取策略： </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p><span class=emphasis><em>连接抓取（Join fetching）</em></span> - Hibernate通过 在<tt class=literal>SELECT</tt>语句使用<tt class=literal>OUTER JOIN</tt>（外连接）来 获得对象的关联实例或者关联集合。 </p>
    <li>
    <p><span class=emphasis><em>查询抓取（Select fetching）</em></span> - 另外发送一条 <tt class=literal>SELECT</tt> 语句抓取当前对象的关联实体或集合。除非你显式的指定<tt class=literal>lazy="false"</tt>禁止 延迟抓取（lazy fetching），否则只有当你真正访问关联关系的时候，才会执行第二条select语句。 </p>
    <li>
    <p><span class=emphasis><em>子查询抓取（Subselect fetching）</em></span> - 另外发送一条<tt class=literal>SELECT</tt> 语句抓取在前面查询到（或者抓取到）的所有实体对象的关联集合。除非你显式的指定<tt class=literal>lazy="false"</tt> 禁止延迟抓取（lazy fetching），否则只有当你真正访问关联关系的时候，才会执行第二条select语句。 </p>
    <li>
    <p><span class=emphasis><em>批量抓取（Batch fetching）</em></span> - 对查询抓取的优化方案， 通过指定一个主键或外键列表，Hibernate使用单条<tt class=literal>SELECT</tt>语句获取一批对象实例或集合。 </p>
    </li>
</ul>
</div>
<p>Hibernate会区分下列各种情况： </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p><span class=emphasis><em>Immediate fetching，立即抓取</em></span> - 当宿主被加载时，关联、集合或属性被立即抓取。 </p>
    <li>
    <p><span class=emphasis><em>Lazy collection fetching，延迟集合抓取</em></span>- 直到应用程序对集合进行了一次操作时，集合才被抓取。（对集合而言这是默认行为。） </p>
    <li>
    <p><span class=emphasis><em>Proxy fetching，代理抓取</em></span> - 对返回单值的关联而言，当其某个方法被调用，而非对其关键字进行get操作时才抓取。 </p>
    <li>
    <p><span class=emphasis><em>Lazy attribute fetching，属性延迟加载</em></span> - 对属性或返回单值的关联而言，当其实例变量被访问的时候进行抓取（需要运行时字节码强化）。这一方法很少是必要的。 </p>
    </li>
</ul>
</div>
<p>这里有两个正交的概念：关联<span class=emphasis><em>何时</em></span>被抓取，以及被<span class=emphasis><em>如何</em></span>抓取（会采用什么样的SQL语句）。不要混淆它们！我们使用<tt class=literal>抓取</tt>来改善性能。我们使用<tt class=literal>延迟</tt>来定义一些契约，对某特定类的某个脱管的实例，知道有哪些数据是可以使用的。 </p>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=performance-fetching-lazy></a>20.1.1.&nbsp;操作延迟加载的关联</h3>
</div>
</div>
<div></div>
</div>
<p>默认情况下，Hibernate 3对集合使用延迟select抓取，对返回单值的关联使用延迟代理抓取。对几乎是所有的应用而言，其绝大多数的关联，这种策略都是有效的。 </p>
<p><span class=emphasis><em>注意:</em></span>假若你设置了<tt class=literal>hibernate.default_batch_fetch_size</tt>,Hibernate会对延迟加载采取批量抓取优化措施（这种优化也可能会在更细化的级别打开）。 </p>
<p>然而，你必须了解延迟抓取带来的一个问题。在一个打开的Hibernate session上下文之外调用延迟集合会导致一次意外。比如： </p>
<pre class=programlisting>s = sessions.openSession();
Transaction tx = s.beginTransaction();
User u = (User) s.createQuery("from User u where u.name=:userName")
.setString("userName", userName).uniqueResult();
Map permissions = u.getPermissions();
tx.commit();
s.close();
Integer accessLevel = (Integer) permissions.get("accounts");  // Error!</pre>
<p>在<tt class=literal>Session</tt>关闭后，permessions集合将是未实例化的、不再可用，因此无法正常载入其状态。 <span class=emphasis><em>Hibernate对脱管对象不支持延迟实例化</em></span>. 这里的修改方法是：将permissions读取数据的代码 移到tx.commit()之前。 </p>
<p>除此之外，通过对关联映射指定<tt class=literal>lazy="false"</tt>,我们也可以使用非延迟的集合或关联。但是， 对绝大部分集合来说，更推荐使用延迟方式抓取数据。如果在你的对象模型中定义了太多的非延迟关联，Hibernate最终几乎需要在每个事务中载入整个数据库到内存中！ </p>
<p>但是，另一方面，在一些特殊的事务中，我们也经常需要使用到连接抓取（它本身上就是非延迟的），以代替查询抓取。 下面我们将会很快明白如何具体的定制Hibernate中的抓取策略。在Hibernate3中，具体选择哪种抓取策略的机制是和选择 单值关联或集合关联相一致的。 </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=performance-fetching-custom></a>20.1.2.&nbsp; 调整抓取策略（Tuning fetch strategies） </h3>
</div>
</div>
<div></div>
</div>
<p>查询抓取（默认的）在N+1查询的情况下是极其脆弱的，因此我们可能会要求在映射文档中定义使用连接抓取： </p>
<pre class=programlisting>&lt;set name="permissions"
fetch="join"&gt;
&lt;key column="userId"/&gt;
&lt;one-to-many class="Permission"/&gt;
&lt;/set</pre>
<pre class=programlisting>&lt;many-to-one name="mother" class="Cat" fetch="join"/&gt;</pre>
<p>在映射文档中定义的抓取策略将会有产生以下影响： </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p>通过<tt class=literal>get()</tt>或<tt class=literal>load()</tt>方法取得数据。 </p>
    <li>
    <p>只有在关联之间进行导航时，才会隐式的取得数据(延迟抓取)。 </p>
    <li>
    <p><tt class=literal>条件查询</tt> </p>
    </li>
</ul>
</div>
<p>通常情况下，我们并不使用映射文档进行抓取策略的定制。更多的是，保持其默认值，然后在特定的事务中， 使用HQL的<tt class=literal>左连接抓取（left join fetch）</tt> 对其进行重载。这将通知 Hibernate在第一次查询中使用外部关联（outer join），直接得到其关联数据。 在<tt class=literal>条件查询</tt> API中，应该调用 <tt class=literal>setFetchMode(FetchMode.JOIN)</tt>语句。 </p>
<p>也许你喜欢仅仅通过条件查询，就可以改变<tt class=literal>get()</tt> 或 <tt class=literal>load()</tt>语句中的数据抓取策略。例如： </p>
<pre class=programlisting>User user = (User) session.createCriteria(User.class)
.setFetchMode("permissions", FetchMode.JOIN)
.add( Restrictions.idEq(userId) )
.uniqueResult();</pre>
<p>（这就是其他ORM解决方案的&#8220;抓取计划(fetch plan)&#8221;在Hibernate中的等价物。） </p>
<p>截然不同的一种避免N+1次查询的方法是，使用二级缓存。 </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=performance-fetching-proxies></a>20.1.3.&nbsp;单端关联代理（Single-ended association proxies） </h3>
</div>
</div>
<div></div>
</div>
<p>在Hinerbate中，对集合的延迟抓取的采用了自己的实现方法。但是，对于单端关联的延迟抓取，则需要采用 其他不同的机制。单端关联的目标实体必须使用代理，Hihernate在运行期二进制级（通过优异的CGLIB库）， 为持久对象实现了延迟载入代理。 </p>
<p>默认的，Hibernate3将会为所有的持久对象产生代理（在启动阶段），然后使用他们实现 <tt class=literal>多对一（many-to-one）</tt>关联和<tt class=literal>一对一（one-to-one）</tt> 关联的延迟抓取。 </p>
<p>在映射文件中，可以通过设置<tt class=literal>proxy</tt>属性为目标class声明一个接口供代理接口使用。 默认的，Hibernate将会使用该类的一个子类。 <span class=emphasis><em>注意：被代理的类必须实现一个至少包可见的默认构造函数，我们建议所有的持久类都应拥有这样的构造函数</em></span> </p>
<p>在如此方式定义一个多态类的时候，有许多值得注意的常见性的问题，例如： </p>
<pre class=programlisting>&lt;class name="Cat" proxy="Cat"&gt;
......
&lt;subclass name="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>其次，代理的&#8220;<tt class=literal>==</tt>&#8221;可能不再成立。 </p>
<pre class=programlisting>Cat cat = (Cat) session.load(Cat.class, id);            // instantiate a Cat proxy
DomesticCat dc =
(DomesticCat) session.load(DomesticCat.class, id);  // acquire 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>第三，你不能对&#8220;final类&#8221;或&#8220;具有final方法的类&#8221;使用CGLIB代理。 </p>
<p>最后，如果你的持久化对象在实例化时需要某些资源（例如，在实例化方法、默认构造方法中）， 那么代理对象也同样需要使用这些资源。实际上，代理类是持久化类的子类。 </p>
<p>这些问题都源于Java的单根继承模型的天生限制。如果你希望避免这些问题，那么你的每个持久化类必须实现一个接口， 在此接口中已经声明了其业务方法。然后，你需要在映射文档中再指定这些接口。例如： </p>
<pre class=programlisting>&lt;class name="CatImpl" proxy="Cat"&gt;
......
&lt;subclass name="DomesticCatImpl" proxy="DomesticCat"&gt;
.....
&lt;/subclass&gt;
&lt;/class&gt;</pre>
<p>这里<tt class=literal>CatImpl</tt>实现了<tt class=literal>Cat</tt>接口， <tt class=literal>DomesticCatImpl</tt>实现<tt class=literal>DomesticCat</tt>接口。 在<tt class=literal>load()</tt>、<tt class=literal>iterate()</tt>方法中就会返回 <tt class=literal>Cat</tt>和<tt class=literal>DomesticCat</tt>的代理对象。 (注意<tt class=literal>list()</tt>并不会返回代理对象。) </p>
<pre class=programlisting>Cat cat = (Cat) session.load(CatImpl.class, catid);
Iterator iter = session.iterate("from CatImpl as cat where cat.name='fritz'");
Cat fritz = (Cat) iter.next();</pre>
<p>这里，对象之间的关系也将被延迟载入。这就意味着，你应该将属性声明为<tt class=literal>Cat</tt>，而不是<tt class=literal>CatImpl</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>
    <p><tt class=literal>hashCode()</tt>方法，如果持久类没有重载<tt class=literal>hashCode()</tt>方法。 </p>
    <li>
    <p>标志符的getter方法。 </p>
    </li>
</ul>
</div>
<p>Hibernate将会识别出那些重载了<tt class=literal>equals()</tt>、或<tt class=literal>hashCode()</tt>方法的持久化类。 </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=performance-fetching-initialization></a>20.1.4.&nbsp;实例化集合和代理（Initializing collections and proxies） </h3>
</div>
</div>
<div></div>
</div>
<p>在<tt class=literal>Session</tt>范围之外访问未初始化的集合或代理，Hibernate将会抛出<tt class=literal>LazyInitializationException</tt>异常。 也就是说，在分离状态下，访问一个实体所拥有的集合，或者访问其指向代理的属性时，会引发此异常。 </p>
<p>有时候我们需要保证某个代理或者集合在Session关闭前就已经被初始化了。 当然，我们可以通过强行调用<tt class=literal>cat.getSex()</tt>或者<tt class=literal>cat.getKittens().size()</tt>之类的方法来确保这一点。 但是这样的程序会造成读者的疑惑，也不符合通常的代码规范。 </p>
<p>静态方法<tt class=literal>Hibernate.initialized()</tt> 为你的应用程序提供了一个便捷的途径来延迟加载集合或代理。 只要它的Session处于open状态，<tt class=literal>Hibernate.initialize(cat)</tt> 将会为cat强制对代理实例化。 同样，<tt class=literal>Hibernate.initialize( cat.getKittens() )</tt> 对kittens的集合具有同样的功能。 </p>
<p>还有另外一种选择，就是保持<tt class=literal>Session</tt>一直处于open状态，直到所有需要的集合或代理都被载入。 在某些应用架构中，特别是对于那些使用Hibernate进行数据访问的代码，以及那些在不同应用层和不同物理进程中使用Hibernate的代码。 在集合实例化时，如何保证<tt class=literal>Session</tt>处于open状态经常会是一个问题。有两种方法可以解决此问题： </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p>在一个基于Web的应用中，可以利用servlet过滤器（filter），在用户请求（request）结束、页面生成 结束时关闭<tt class=literal>Session</tt>（这里使用了<span class=emphasis><em>在展示层保持打开Session模式（Open Session in View）</em></span>）， 当然，这将依赖于应用框架中异常需要被正确的处理。在返回界面给用户之前，乃至在生成界面过程中发生异常的情况下， 正确关闭<tt class=literal>Session</tt>和结束事务将是非常重要的， Servlet过滤器必须如此访问<tt class=literal>Session</tt>，才能保证正确使用Session。 我们推荐使用<tt class=literal>ThreadLocal</tt> 变量保存当前的<tt class=literal>Session</tt> （可以参考<a title=1.4.&nbsp;与Cat同乐 href="file:///E:/_DataBank/_JavaHelp/Hibernatehelp/quickstart.html#quickstart-playingwithcats" tppabs="http://www.hibernate.org/hib_docs/v3/reference/zh-cn/html/quickstart.html#quickstart-playingwithcats"><u><font color=#0000ff>第&nbsp;1.4&nbsp;节 &#8220;与Cat同乐&#8221;</font></u></a>的例子实现）。 </p>
    <li>
    <p>在一个拥有单独业务层的应用中，业务层必须在返回之前，为web层&#8220;准备&#8221;好其所需的数据集合。这就意味着 业务层应该载入所有表现层/web层所需的数据，并将这些已实例化完毕的数据返回。通常，应用程序应该 为web层所需的每个集合调用<tt class=literal>Hibernate.initialize()</tt>（这个调用必须发生咱session关闭之前）； 或者使用带有<tt class=literal>FETCH</tt>从句，或<tt class=literal>FetchMode.JOIN</tt>的Hibernate查询， 事先取得所有的数据集合。如果你在应用中使用了<span class=emphasis><em>Command</em></span>模式，代替<span class=emphasis><em>Session Facade</em></span> ， 那么这项任务将会变得简单的多。 </p>
    <li>
    <p>你也可以通过<tt class=literal>merge()</tt>或<tt class=literal>lock()</tt>方法，在访问未实例化的集合（或代理）之前， 为先前载入的对象绑定一个新的<tt class=literal>Session</tt>。 显然，Hibernate将不会，也不<span class=emphasis><em>应该</em></span>自动完成这些任务，因为这将引入一个特殊的事务语义。 </p>
    </li>
</ul>
</div>
<p>有时候，你并不需要完全实例化整个大的集合，仅需要了解它的部分信息（例如其大小）、或者集合的部分内容。 </p>
<p>你可以使用集合过滤器得到其集合的大小，而不必实例化整个集合： </p>
<pre class=programlisting>( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()</pre>
<p>这里的<tt class=literal>createFilter()</tt>方法也可以被用来有效的抓取集合的部分内容，而无需实例化整个集合： </p>
<pre class=programlisting>s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();</pre>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=performance-fetching-batch></a>20.1.5.&nbsp;使用批量抓取（Using batch fetching） </h3>
</div>
</div>
<div></div>
</div>
<p>Hibernate可以充分有效的使用批量抓取，也就是说，如果仅一个访问代理（或集合），那么Hibernate将不载入其他未实例化的代理。 批量抓取是延迟查询抓取的优化方案，你可以在两种批量抓取方案之间进行选择：在类级别和集合级别。 </p>
<p>类/实体级别的批量抓取很容易理解。假设你在运行时将需要面对下面的问题：你在一个<tt class=literal>Session</tt>中载入了25个 <tt class=literal>Cat</tt>实例，每个<tt class=literal>Cat</tt>实例都拥有一个引用成员<tt class=literal>owner</tt>， 其指向<tt class=literal>Person</tt>，而<tt class=literal>Person</tt>类是代理，同时<tt class=literal>lazy="true"</tt>。 如果你必须遍历整个cats集合，对每个元素调用<tt class=literal>getOwner()</tt>方法，Hibernate将会默认的执行25次<tt class=literal>SELECT</tt>查询， 得到其owner的代理对象。这时，你可以通过在映射文件的<tt class=literal>Person</tt>属性，显式声明<tt class=literal>batch-size</tt>，改变其行为： </p>
<pre class=programlisting>&lt;class name="Person" batch-size="10"&gt;...&lt;/class&gt;</pre>
<p>随之，Hibernate将只需要执行三次查询，分别为10、10、 5。 </p>
<p>你也可以在集合级别定义批量抓取。例如，如果每个<tt class=literal>Person</tt>都拥有一个延迟载入的<tt class=literal>Cats</tt>集合， 现在，<tt class=literal>Sesssion</tt>中载入了10个person对象，遍历person集合将会引起10次<tt class=literal>SELECT</tt>查询， 每次查询都会调用<tt class=literal>getCats()</tt>方法。如果你在<tt class=literal>Person</tt>的映射定义部分，允许对<tt class=literal>cats</tt>批量抓取, 那么，Hibernate将可以预先抓取整个集合。请看例子： </p>
<pre class=programlisting>&lt;class name="Person"&gt;
&lt;set name="cats" batch-size="3"&gt;
...
&lt;/set&gt;
&lt;/class&gt;</pre>
<p>如果整个的<tt class=literal>batch-size</tt>是3（笔误？），那么Hibernate将会分四次执行<tt class=literal>SELECT</tt>查询， 按照3、3、3、1的大小分别载入数据。这里的每次载入的数据量还具体依赖于当前<tt class=literal>Session</tt>中未实例化集合的个数。 </p>
<p>如果你的模型中有嵌套的树状结构，例如典型的帐单－原料结构（bill-of-materials pattern），集合的批量抓取是非常有用的。 （尽管在更多情况下对树进行读取时，<span class=emphasis><em>嵌套集合（nested set）</em></span>或<span class=emphasis><em>原料路径(materialized path)</em></span>（&#215;&#215;） 是更好的解决方法。） </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=performance-fetching-subselect></a>20.1.6.&nbsp;使用子查询抓取（Using subselect fetching） </h3>
</div>
</div>
<div></div>
</div>
<p>假若一个延迟集合或单值代理需要抓取，Hibernate会使用一个subselect重新运行原来的查询，一次性读入所有的实例。这和批量抓取的实现方法是一样的，不会有破碎的加载。 </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=performance-fetching-lazyproperties></a>20.1.7.&nbsp;使用延迟属性抓取（Using lazy property fetching） </h3>
</div>
</div>
<div></div>
</div>
<p>Hibernate3对单独的属性支持延迟抓取，这项优化技术也被称为<span class=emphasis><em>组抓取（fetch groups）</em></span>。 请注意，该技术更多的属于市场特性。在实际应用中，优化行读取比优化列读取更重要。但是，仅载入类的部分属性在某些特定情况下会有用，例如在原有表中拥有几百列数据、数据模型无法改动的情况下。 </p>
<p>可以在映射文件中对特定的属性设置<tt class=literal>lazy</tt>，定义该属性为延迟载入。 </p>
<pre class=programlisting>&lt;class name="Document"&gt;
&lt;id name="id"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;property name="name" not-null="true" length="50"/&gt;
&lt;property name="summary" not-null="true" length="200" lazy="true"/&gt;
&lt;property name="text" not-null="true" length="2000" lazy="true"/&gt;
&lt;/class&gt;</pre>
<p>属性的延迟载入要求在其代码构建时加入二进制指示指令（bytecode instrumentation），如果你的持久类代码中未含有这些指令， Hibernate将会忽略这些属性的延迟设置，仍然将其直接载入。 </p>
<p>你可以在Ant的Task中，进行如下定义，对持久类代码加入&#8220;二进制指令。&#8221; </p>
<pre class=programlisting>&lt;target name="instrument" depends="compile"&gt;
&lt;taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask"&gt;
&lt;classpath path="${jar.path}"/&gt;
&lt;classpath path="${classes.dir}"/&gt;
&lt;classpath refid="lib.class.path"/&gt;
&lt;/taskdef&gt;
&lt;instrument verbose="true"&gt;
&lt;fileset dir="${testclasses.dir}/org/hibernate/auction/model"&gt;
&lt;include name="*.class"/&gt;
&lt;/fileset&gt;
&lt;/instrument&gt;
&lt;/target&gt;</pre>
<p>还有一种可以优化的方法，它使用HQL或条件查询的投影（projection）特性，可以避免读取非必要的列， 这一点至少对只读事务是非常有用的。它无需在代码构建时&#8220;二进制指令&#8221;处理，因此是一个更加值得选择的解决方法。 </p>
<p>有时你需要在HQL中通过<tt class=literal>抓取所有属性</tt>，强行抓取所有内容。 </p>
</div>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=performance-cache></a>20.2.&nbsp;二级缓存（The Second Level Cache） </h2>
</div>
</div>
<div></div>
</div>
<p>Hibernate的<tt class=literal>Session</tt>在事务级别进行持久化数据的缓存操作。 当然，也有可能分别为每个类（或集合)，配置集群、或JVM级别(<tt class=literal>SessionFactory级别</tt>)的缓存。 你甚至可以为之插入一个集群的缓存。注意，缓存永远不知道其他应用程序对持久化仓库（数据库）可能进行的修改 （即使可以将缓存数据设定为定期失效）。 </p>
<p>默认情况下，Hibernate使用EHCache进行JVM级别的缓存（目前，Hibernate已经废弃了对JCS的支持，未来版本中将会去掉它）。 你可以通过设置<tt class=literal>hibernate.cache.provider_class</tt>属性，指定其他的缓存策略， 该缓存策略必须实现<tt class=literal>org.hibernate.cache.CacheProvider</tt>接口。 </p>
<div class=table><a name=cacheproviders></a>
<p class=title><strong>表&nbsp;20.1.&nbsp; 缓存策略提供商（Cache Providers） </strong></p>
<table summary="&#10;&#9;&#9;&#9;&#9;缓存策略提供商（Cache Providers）&#10;&#9;&#9;&#9;" border=1>
    <colgroup>
    <col align=left>
    <col align=left>
    <col align=left>
    <col align=left>
    <col align=left></colgroup>
    <thead>
        <tr>
            <th align=left>Cache</th>
            <th align=left>Provider class</th>
            <th align=left>Type</th>
            <th align=left>Cluster Safe</th>
            <th align=left>Query Cache Supported</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td align=left>Hashtable (not intended for production use)</td>
            <td align=left><tt class=literal>org.hibernate.cache.HashtableCacheProvider</tt></td>
            <td align=left>memory</td>
            <td align=left>&nbsp;</td>
            <td align=left>yes</td>
        </tr>
        <tr>
            <td align=left>EHCache</td>
            <td align=left><tt class=literal>org.hibernate.cache.EhCacheProvider</tt></td>
            <td align=left>memory, disk</td>
            <td align=left>&nbsp;</td>
            <td align=left>yes</td>
        </tr>
        <tr>
            <td align=left>OSCache</td>
            <td align=left><tt class=literal>org.hibernate.cache.OSCacheProvider</tt></td>
            <td align=left>memory, disk</td>
            <td align=left>&nbsp;</td>
            <td align=left>yes</td>
        </tr>
        <tr>
            <td align=left>SwarmCache</td>
            <td align=left><tt class=literal>org.hibernate.cache.SwarmCacheProvider</tt></td>
            <td align=left>clustered (ip multicast)</td>
            <td align=left>yes (clustered invalidation)</td>
            <td align=left>&nbsp;</td>
        </tr>
        <tr>
            <td align=left>JBoss TreeCache</td>
            <td align=left><tt class=literal>org.hibernate.cache.TreeCacheProvider</tt></td>
            <td align=left>clustered (ip multicast), transactional</td>
            <td align=left>yes (replication)</td>
            <td align=left>yes (clock sync req.)</td>
        </tr>
    </tbody>
</table>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=performance-cache-mapping></a>20.2.1.&nbsp;缓存映射（Cache mappings） </h3>
</div>
</div>
<div></div>
</div>
<p>类或者集合映射的&#8220;<tt class=literal>&lt;cache&gt;</tt>元素&#8221;可以有下列形式： </p>
<div class=programlistingco>
<pre class=programlisting>&lt;cache
usage="transactional|read-write|nonstrict-read-write|read-only"  <span class=co>(1)</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>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>另外(首选?), 你可以在hibernate.cfg.xml中指定<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>20.2.2.&nbsp;策略：只读缓存（Strategy: read only） </h3>
</div>
</div>
<div></div>
</div>
<p>如果你的应用程序只需读取一个持久化类的实例，而无需对其修改， 那么就可以对其进行<tt class=literal>只读</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>20.2.3.&nbsp; 策略:读/写缓存（Strategy: read/write） </h3>
</div>
</div>
<div></div>
</div>
<p>如果应用程序需要更新数据，那么使用<tt class=literal>读/写缓存</tt> 比较合适。 如果应用程序要求&#8220;序列化事务&#8221;的隔离级别（serializable transaction isolation level），那么就决不能使用这种缓存策略。 如果在JTA环境中使用缓存，你必须指定<tt class=literal>hibernate.transaction.manager_lookup_class</tt>属性的值， 通过它，Hibernate才能知道该应用程序中JTA的<tt class=literal>TransactionManager</tt>的具体策略。 在其它环境中，你必须保证在<tt class=literal>Session.close()</tt>、或<tt class=literal>Session.disconnect()</tt>调用前， 整个事务已经结束。 如果你想在集群环境中使用此策略，你必须保证底层的缓存实现支持锁定(locking)。Hibernate内置的缓存策略并不支持锁定功能。 </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>20.2.4.&nbsp; 策略:非严格读/写缓存（Strategy: nonstrict read/write） </h3>
</div>
</div>
<div></div>
</div>
<p>如果应用程序只偶尔需要更新数据（也就是说，两个事务同时更新同一记录的情况很不常见），也不需要十分严格的事务隔离， 那么比较适合使用<tt class=literal>非严格读/写缓存</tt>策略。如果在JTA环境中使用该策略， 你必须为其指定<tt class=literal>hibernate.transaction.manager_lookup_class</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>20.2.5.&nbsp; 策略:事务缓存（transactional） </h3>
</div>
</div>
<div></div>
</div>
<p>Hibernate的<tt class=literal>事务缓存</tt>策略提供了全事务的缓存支持， 例如对JBoss TreeCache的支持。这样的缓存只能用于JTA环境中，你必须指定 为其<tt class=literal>hibernate.transaction.manager_lookup_class</tt>属性。 </p>
</div>
<p>没有一种缓存提供商能够支持上列的所有缓存并发策略。下表中列出了各种提供器、及其各自适用的并发策略。 </p>
<div class=table><a name=d0e13479></a>
<p class=title><strong>表&nbsp;20.2.&nbsp; 各种缓存提供商对缓存并发策略的支持情况（Cache Concurrency Strategy Support） </strong></p>
<table summary="&#10;&#9;&#9;&#9;各种缓存提供商对缓存并发策略的支持情况（Cache Concurrency Strategy Support）&#10;&#9;&#9;&#9;" 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>&nbsp;</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>&nbsp;</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>&nbsp;</td>
        </tr>
        <tr>
            <td align=left>SwarmCache</td>
            <td align=left>yes</td>
            <td align=left>yes</td>
            <td align=left>&nbsp;</td>
            <td align=left>&nbsp;</td>
        </tr>
        <tr>
            <td align=left>JBoss TreeCache</td>
            <td align=left>yes</td>
            <td align=left>&nbsp;</td>
            <td align=left>&nbsp;</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>20.3.&nbsp; 管理缓存（Managing the caches） </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>get()</tt>、<tt class=literal>list()</tt>、<tt class=literal>iterate()</tt> 或<tt class=literal>scroll()</tt>方法获得一个对象时, 该对象都将被加入到<tt class=literal>Session</tt>的内部缓存中。 </p>
<p>当随后flush()方法被调用时，对象的状态会和数据库取得同步。 如果你不希望此同步操作发生，或者你正处理大量对象、需要对有效管理内存时，你可以调用<tt class=literal>evict()</tt> 方法，从一级缓存中去掉这些对象及其集合。 </p>
<pre class=programlisting>ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
while ( cats.next() ) {
Cat cat = (Cat) cats.get(0);
doSomethingWithACat(cat);
sess.evict(cat);
}</pre>
<p>Session还提供了一个<tt class=literal>contains()</tt>方法，用来判断某个实例是否处于当前session的缓存中。 </p>
<p>如若要把所有的对象从session缓存中彻底清除，则需要调用<tt class=literal>Session.clear()</tt>。 </p>
<p>对于二级缓存来说，在<tt class=literal>SessionFactory</tt>中定义了许多方法， 清除缓存中实例、整个类、集合实例或者整个集合。 </p>
<pre class=programlisting>sessionFactory.evict(Cat.class, catId); //evict a particular Cat
sessionFactory.evict(Cat.class);  //evict all Cats
sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections</pre>
<p><tt class=literal>CacheMode</tt>参数用于控制具体的Session如何与二级缓存进行交互。 </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p><tt class=literal>CacheMode.NORMAL</tt> - 从二级缓存中读、写数据。 </p>
    <li>
    <p><tt class=literal>CacheMode.GET</tt> - 从二级缓存中读取数据，仅在数据更新时对二级缓存写数据。 </p>
    <li>
    <p><tt class=literal>CacheMode.PUT</tt> - 仅向二级缓存写数据，但不从二级缓存中读数据。 </p>
    <li>
    <p><tt class=literal>CacheMode.REFRESH</tt> - 仅向二级缓存写数据，但不从二级缓存中读数据。通过 <tt class=literal>hibernate.cache.use_minimal_puts</tt>的设置，强制二级缓存从数据库中读取数据，刷新缓存内容。 </p>
    </li>
</ul>
</div>
<p>如若需要查看二级缓存或查询缓存区域的内容，你可以使用<tt class=literal>统计（Statistics）</tt> API。 </p>
<pre class=programlisting>Map cacheEntries = sessionFactory.getStatistics()
.getSecondLevelCacheStatistics(regionName)
.getEntries();</pre>
<p>此时，你必须手工打开统计选项。可选的，你可以让Hibernate更人工可读的方式维护缓存内容。 </p>
<pre class=programlisting>hibernate.generate_statistics true
hibernate.cache.use_structured_entries true</pre>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=performance-querycache></a>20.4.&nbsp;查询缓存（The Query Cache） </h2>
</div>
</div>
<div></div>
</div>
<p>查询的结果集也可以被缓存。只有当经常使用同样的参数进行查询时，这才会有些用处。 要使用查询缓存，首先你必须打开它： </p>
<pre class=programlisting>hibernate.cache.use_query_cache true</pre>
<p>该设置将会创建两个缓存区域 - 一个用于保存查询结果集(<tt class=literal>org.hibernate.cache.StandardQueryCache</tt>)； 另一个则用于保存最近查询的一系列表的时间戳(<tt class=literal>org.hibernate.cache.UpdateTimestampsCache</tt>)。 请注意：在查询缓存中，它并不缓存结果集中所包含的实体的确切状态；它只缓存这些实体的标识符属性的值、以及各值类型的结果。 所以查询缓存通常会和二级缓存一起使用。 </p>
<p>绝大多数的查询并不能从查询缓存中受益，所以Hibernate默认是不进行查询缓存的。如若需要进行缓存，请调用 <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>
<p>如果查询需要强行刷新其查询缓存区域，那么你应该调用<tt class=literal>Query.setCacheMode(CacheMode.REFRESH)</tt>方法。 这对在其他进程中修改底层数据（例如，不通过Hibernate修改数据），或对那些需要选择性更新特定查询结果集的情况特别有用。 这是对<tt class=literal>SessionFactory.evictQueries()</tt>的更为有效的替代方案，同样可以清除查询缓存区域。 </p>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=performance-collections></a>20.5.&nbsp; 理解集合性能（Understanding Collection performance） </h2>
</div>
</div>
<div></div>
</div>
<p>前面我们已经对集合进行了足够的讨论。本段中，我们将着重讲述集合在运行时的事宜。 </p>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=performance-collections-taxonomy></a>20.5.1.&nbsp; 分类（Taxonomy） </h3>
</div>
</div>
<div></div>
</div>
<p>Hibernate定义了三种基本类型的集合： </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p>值数据集合 </p>
    <li>
    <p>一对多关联 </p>
    <li>
    <p>多对多关联 </p>
    </li>
</ul>
</div>
<p>这个分类是区分了不同的表和外键关系类型，但是它没有告诉我们关系模型的所有内容。 要完全理解他们的关系结构和性能特点，我们必须同时考虑&#8220;用于Hibernate更新或删除集合行数据的主键的结构&#8221;。 因此得到了如下的分类： </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p>有序集合类 </p>
    <li>
    <p>集合（sets） </p>
    <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><tt class=literal>&lt;idbag&gt;</tt>映射定义了代理键，因此它总是可以很高效的被更新。事实上， <tt class=literal>&lt;idbag&gt;</tt>拥有着最好的性能表现。 </p>
<p>Bag是最差的。因为bag允许重复的元素值，也没有索引字段，因此不可能定义主键。 Hibernate无法判断出重复的行。当这种集合被更改时，Hibernate将会先完整地移除 （通过一个(in a single <tt class=literal>DELETE</tt>)）整个集合，然后再重新创建整个集合。 因此Bag是非常低效的。 </p>
<p>请注意：对于一对多关联来说，&#8220;主键&#8221;很可能并不是数据库表的物理主键。 但就算在此情况下，上面的分类仍然是有用的。（它仍然反映了Hibernate在集合的各数据行中是如何进行&#8220;定位&#8221;的。） </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=performance-collections-mostefficientupdate></a>20.5.2.&nbsp; Lists, maps 和sets用于更新效率最高 </h3>
</div>
</div>
<div></div>
</div>
<p>根据我们上面的讨论，显然有序集合类型和大多数set都可以在增加、删除、修改元素中拥有最好的性能。 </p>
<p>可论证的是对于多对多关联、值数据集合而言，有序集合类比集合(set)有一个好处。因为<tt class=literal>Set</tt>的内在结构， 如果&#8220;改变&#8221;了一个元素，Hibernate并不会<tt class=literal>更新（UPDATE）</tt>这一行。 对于<tt class=literal>Set</tt>来说，只有在<tt class=literal>插入（INSERT）</tt>和<tt class=literal>删除（DELETE）</tt> 操作时&#8220;改变&#8221;才有效。再次强调：这段讨论对&#8220;一对多关联&#8221;并不适用。 </p>
<p>注意到数组无法延迟载入，我们可以得出结论，list, map和idbags是最高效的（非反向）集合类型，set则紧随其后。 在Hibernate中，set应该时最通用的集合类型，这时因为&#8220;set&#8221;的语义在关系模型中是最自然的。 </p>
<p>但是，在设计良好的Hibernate领域模型中，我们通常可以看到更多的集合事实上是带有<tt class=literal>inverse="true"</tt> 的一对多的关联。对于这些关联，更新操作将会在多对一的这一端进行处理。因此对于此类情况，无需考虑其集合的更新性能。 </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=performance-collections-mostefficentinverse></a>20.5.3.&nbsp; Bag和list是反向集合类中效率最高的 </h3>
</div>
</div>
<div></div>
</div>
<p>在把bag扔进水沟之前，你必须了解，在一种情况下，bag的性能(包括list)要比set高得多： 对于指明了<tt class=literal>inverse="true"</tt>的集合类（比如说，标准的双向的一对多关联）， 我们可以在未初始化(fetch)包元素的情况下直接向bag或list添加新元素！ 这是因为<tt class=literal>Collection.add()</tt>)或者<tt class=literal>Collection.addAll()</tt> 方法 对bag或者List总是返回true（这点与与Set不同）。因此对于下面的相同代码来说，速度会快得多。 </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>20.5.4.&nbsp; 一次性删除（One shot delete） </h3>
</div>
</div>
<div></div>
</div>
<p>偶尔的，逐个删除集合类中的元素是相当低效的。Hibernate并没那么笨， 如果你想要把整个集合都删除（比如说调用list.clear()），Hibernate只需要一个DELETE就搞定了。 </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>
    <p>删除整个集合类（只用一句DELETE语句），然后增加5个数据。 </p>
    </li>
</ul>
</div>
<p>Hibernate还没那么聪明，知道第二种选择可能会比较快。 （也许让Hibernate不这么聪明也是好事，否则可能会引发意外的&#8220;数据库触发器&#8221;之类的问题。） </p>
<p>幸运的是，你可以强制使用第二种策略。你需要取消原来的整个集合类（解除其引用）， 然后再返回一个新的实例化的集合类，只包含需要的元素。有些时候这是非常有用的。 </p>
<p>显然，一次性删除并不适用于被映射为<tt class=literal>inverse="true"</tt>的集合。 </p>
</div>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=performance-monitoring></a>20.6.&nbsp; 监测性能（Monitoring performance） </h2>
</div>
</div>
<div></div>
</div>
<p>没有监测和性能参数而进行优化是毫无意义的。Hibernate为其内部操作提供了一系列的示意图，因此可以从 每个<tt class=literal>SessionFactory</tt>抓取其统计数据。 </p>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=performance-monitoring-sf></a>20.6.1.&nbsp; 监测SessionFactory </h3>
</div>
</div>
<div></div>
</div>
<p>你可以有两种方式访问<tt class=literal>SessionFactory</tt>的数据记录，第一种就是自己直接调用 <tt class=literal>sessionFactory.getStatistics()</tt>方法读取、显示<tt class=literal>统计</tt>数据。 </p>
<p>此外，如果你打开<tt class=literal>StatisticsService</tt> MBean选项，那么Hibernate则可以使用JMX技术 发布其数据记录。你可以让应用中所有的<tt class=literal>SessionFactory</tt>同时共享一个MBean，也可以每个 SessionFactory分配一个MBean。下面的代码即是其演示代码： </p>
<pre class=programlisting>// MBean service registration for a specific SessionFactory
Hashtable tb = new Hashtable();
tb.put("type", "statistics");
tb.put("sessionFactory", "myFinancialApp");
ObjectName on = new ObjectName("hibernate", tb); // MBean object name
StatisticsService stats = new StatisticsService(); // MBean implementation
stats.setSessionFactory(sessionFactory); // Bind the stats to a SessionFactory
server.registerMBean(stats, on); // Register the Mbean on the server</pre>
<pre class=programlisting>// MBean service registration for all SessionFactory's
Hashtable tb = new Hashtable();
tb.put("type", "statistics");
tb.put("sessionFactory", "all");
ObjectName on = new ObjectName("hibernate", tb); // MBean object name
StatisticsService stats = new StatisticsService(); // MBean implementation
server.registerMBean(stats, on); // Register the MBean on the server</pre>
<p>TODO：仍需要说明的是：在第一个例子中，我们直接得到和使用MBean；而在第二个例子中，在使用MBean之前 我们则需要给出SessionFactory的JNDI名，使用<tt class=literal>hibernateStatsBean.setSessionFactoryJNDIName("my/JNDI/Name")</tt> 得到SessionFactory，然后将MBean保存于其中。 </p>
<p>你可以通过以下方法打开或关闭<tt class=literal>SessionFactory</tt>的监测功能： </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p>在配置期间，将<tt class=literal>hibernate.generate_statistics</tt>设置为<tt class=literal>true</tt>或<tt class=literal>false</tt>； </p>
    </li>
</ul>
</div>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p>在运行期间，则可以可以通过<tt class=literal>sf.getStatistics().setStatisticsEnabled(true)</tt> 或<tt class=literal>hibernateStatsBean.setStatisticsEnabled(true)</tt> </p>
    </li>
</ul>
</div>
<p>你也可以在程序中调用<tt class=literal>clear()</tt>方法重置统计数据，调用<tt class=literal>logSummary()</tt> 在日志中记录（info级别）其总结。 </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=performance-monitoring-metrics></a>20.6.2.&nbsp; 数据记录（Metrics） </h3>
</div>
</div>
<div></div>
</div>
<p>Hibernate提供了一系列数据记录，其记录的内容包括从最基本的信息到与具体场景的特殊信息。所有的测量值都可以由 <tt class=literal>Statistics</tt>接口进行访问，主要分为三类： </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p>使用<tt class=literal>Session</tt>的普通数据记录，例如打开的Session的个数、取得的JDBC的连接数等； </p>
    <li>
    <p>实体、集合、查询、缓存等内容的统一数据记录 </p>
    <li>
    <p>和具体实体、集合、查询、缓存相关的详细数据记录 </p>
    </li>
</ul>
</div>
<p>例如：你可以检查缓存的命中成功次数，缓存的命中失败次数，实体、集合和查询的使用概率，查询的平均时间等。请注意 Java中时间的近似精度是毫秒。Hibernate的数据精度和具体的JVM有关，在有些平台上其精度甚至只能精确到10秒。 </p>
<p>你可以直接使用getter方法得到全局数据记录（例如，和具体的实体、集合、缓存区无关的数据），你也可以在具体查询中通过标记实体名、 或HQL、SQL语句得到某实体的数据记录。请参考<tt class=literal>Statistics</tt>、<tt class=literal>EntityStatistics</tt>、 <tt class=literal>CollectionStatistics</tt>、<tt class=literal>SecondLevelCacheStatistics</tt>、 和<tt class=literal>QueryStatistics</tt>的API文档以抓取更多信息。下面的代码则是个简单的例子： </p>
<pre class=programlisting>Statistics stats = HibernateUtil.sessionFactory.getStatistics();
double queryCacheHitCount  = stats.getQueryCacheHitCount();
double queryCacheMissCount = stats.getQueryCacheMissCount();
double queryCacheHitRatio =
queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount);
log.info("Query Hit ratio:" + queryCacheHitRatio);
EntityStatistics entityStats =
stats.getEntityStatistics( Cat.class.getName() );
long changes =
entityStats.getInsertCount()
+ entityStats.getUpdateCount()
+ entityStats.getDeleteCount();
log.info(Cat.class.getName() + " changed " + changes + "times"  );</pre>
<p>如果你想得到所有实体、集合、查询和缓存区的数据，你可以通过以下方法获得实体、集合、查询和缓存区列表： <tt class=literal>getQueries()</tt>、<tt class=literal>getEntityNames()</tt>、 <tt class=literal>getCollectionRoleNames()</tt>和 <tt class=literal>getSecondLevelCacheRegionNames()</tt>。 </p>
</div>
</div>
<table cellSpacing=0 cellPadding=0 width=760 align=center border=0>
    <tbody>
        <tr>
            <td class=title vAlign=center align=middle height=56><strong><font color=#ff0000 size=3>Hibernate程序性能优化的考虑要点<!-- #EndEditable --></font></strong></td>
        </tr>
        <tr>
            <td class=formtitle align=middle height=40>MENGCHUCHEN<!-- #BeginEditable "2" --></td>
        </tr>
    </tbody>
</table>
<table height=65 cellSpacing=0 cellPadding=0 width=760 align=center border=0>
    <tbody>
        <tr>
            <td class=content height=65><!-- #BeginEditable "3" -->
            <table class=content width="100%" align=center border=0>
                <tbody>
                    <tr>
                        <td class=content>
                        <p class=content>本文依照HIBERNATE帮助文档，一些网络书籍及项目经验整理而成，只提供要点和思路，具体做法可以留言探讨，或是找一些更详细更有针对性的资料。</p>
                        <p class=content>初用HIBERNATE的人也许都遇到过性能问题，实现同一功能，用HIBERNATE与用JDBC性能相差十几倍很正常，如果不及早调整，很可能影响整个项目的进度。</p>
                        <p class=content>大体上，对于HIBERNATE性能调优的主要考虑点如下:</p>
                        <ul>
                            <li>数据库设计调整
                            <li>HQL优化
                            <li>API的正确使用(如根据不同的业务类型选用不同的集合及查询API)
                            <li>主配置参数(日志，查询缓存，fetch_size, batch_size等)
                            <li>映射文件优化(ID生成策略，二级缓存，延迟加载，关联优化)
                            <li>一级缓存的管理
                            <li>针对二级缓存，还有许多特有的策略
                            <li>事务控制策略。 </li>
                        </ul>
                        <p class=content><strong>1、 数据库设计</strong></p>
                        <p class=content>a) 降低关联的复杂性</p>
                        <p class=content>b) 尽量不使用联合主键</p>
                        <p class=content>c) ID的生成机制，不同的数据库所提供的机制并不完全一样</p>
                        <p class=content>d) 适当的冗余数据，不过分追求高范式</p>
                        <p class=content><strong>2、 HQL优化</strong></p>
                        <p class=content>HQL如果抛开它同HIBERNATE本身一些缓存机制的关联，HQL的优化技巧同普通的SQL优化技巧一样，可以很容易在网上找到一些经验之谈。</p>
                        <p class=content><strong>3、 主配置</strong></p>
                        <p class=content>a) 查询缓存，同下面讲的缓存不太一样，它是针对HQL语句的缓存，即完全一样的语句再次执行时可以利用缓存数据。但是，查询缓存在一个交易系统(数据变更频繁，查询条件相同的机率并不大)中可能会起反作用:它会白白耗费大量的系统资源但却难以派上用场。</p>
                        <p class=content>b) fetch_size，同JDBC的相关参数作用类似，参数并不是越大越好，而应根据业务特征去设置</p>
                        <p class=content>c) batch_size同上。</p>
                        <p class=content>d) 生产系统中，切记要关掉SQL语句打印。</p>
                        <p class=content><strong>4、 缓存</strong></p>
                        <p class=content>a) 数据库级缓存:这级缓存是最高效和安全的，但不同的数据库可管理的层次并不一样，比如，在ORACLE中，可以在建表时指定将整个表置于缓存当中。</p>
                        <p class=content>b) SESSION缓存:在一个HIBERNATE SESSION有效，这级缓存的可干预性不强，大多于HIBERNATE自动管理，但它提供清除缓存的方法，这在大批量增加/更新操作是有效的。比如，同时增加十万条记录，按常规方式进行，很可能会发现OutofMemeroy的异常，这时可能需要手动清除这一级缓存:Session.evict以及Session.clear</p>
                        <p class=content>c) 应用缓存:在一个SESSIONFACTORY中有效，因此也是优化的重中之重，因此，各类策略也考虑的较多，在将数据放入这一级缓存之前，需要考虑一些前提条件:</p>
                        <p class=content>i. 数据不会被第三方修改(比如，是否有另一个应用也在修改这些数据?)</p>
                        <p class=content>ii. 数据不会太大</p>
                        <p class=content>iii. 数据不会频繁更新(否则使用CACHE可能适得其反)</p>
                        <p class=content>iv. 数据会被频繁查询</p>
                        <p class=content>v. 数据不是关键数据(如涉及钱，安全等方面的问题)。</p>
                        <p class=content>缓存有几种形式，可以在映射文件中配置:read-only(只读，适用于很少变更的静态数据/历史数据)，nonstrict-read-write，read-write(比较普遍的形式，效率一般)，transactional(JTA中，且支持的缓存产品较少)</p>
                        <p class=content>d) 分布式缓存:同c)的配置一样，只是缓存产品的选用不同，在目前的HIBERNATE中可供选择的不多，oscache, jboss cache，目前的大多数项目，对它们的用于集群的使用(特别是关键交易系统)都持保守态度。在集群环境中，只利用数据库级的缓存是最安全的。</p>
                        <p class=content><strong>5、 延迟加载</strong></p>
                        <p class=content>a) 实体延迟加载:通过使用动态代理实现</p>
                        <p class=content>b) 集合延迟加载:通过实现自有的SET/LIST，HIBERNATE提供了这方面的支持</p>
                        <p class=content>c) 属性延迟加载:</p>
                        <p class=content><strong>6、 方法选用</strong></p>
                        <p class=content>a) 完成同样一件事，HIBERNATE提供了可供选择的一些方式，但具体使用什么方式，可能用性能/代码都会有影响。显示，一次返回十万条记录(List/Set/Bag/Map等)进行处理，很可能导致内存不够的问题，而如果用基于游标(ScrollableResults)或Iterator的结果集，则不存在这样的问题。</p>
                        <p class=content>b) Session的load/get方法，前者会使用二级缓存，而后者则不使用。</p>
                        <p class=content>c) Query和list/iterator，如果去仔细研究一下它们，你可能会发现很多有意思的情况，二者主要区别(如果使用了Spring，在HibernateTemplate中对应find,iterator方法):</p>
                        <p class=content>i. list只能利用查询缓存(但在交易系统中查询缓存作用不大)，无法利用二级缓存中的单个实体，但list查出的对象会写入二级缓存，但它一般只生成较少的执行SQL语句，很多情况就是一条(无关联)。</p>
                        <p class=content>ii. iterator则可以利用二级缓存，对于一条查询语句，它会先从数据库中找出所有符合条件的记录的ID，再通过ID去缓存找，对于缓存中没有的记录，再构造语句从数据库中查出，因此很容易知道，如果缓存中没有任何符合条件的记录，使用iterator会产生N+1条SQL语句(N为符合条件的记录数)</p>
                        <p class=content>iii. 通过iterator，配合缓存管理API，在海量数据查询中可以很好的解决内存问题，如:</p>
                        <table width="80%" border=1>
                            <tbody>
                                <tr>
                                    <td class=content bgColor=#cccccc>
                                    <p class=content>　while(it.hasNext()){</p>
                                    <p class=content>　　YouObject object = (YouObject)it.next();</p>
                                    <p class=content>　　session.evict(youObject);</p>
                                    <p class=content>　　sessionFactory.evice(YouObject.class, youObject.getId());</p>
                                    <p class=content>　　}</p>
                                    </td>
                                </tr>
                            </tbody>
                        </table>
                        <p class=content>如果用list方法，很可能就出OutofMemory错误了。</p>
                        <p class=content>iv. 通过上面的说明，我想你应该知道如何去使用这两个方法了。</p>
                        <p class=content><strong>7、 集合的选用</strong></p>
                        <p class=content>在HIBERNATE 3.1文档的&#8220;19.5. Understanding Collection performance&#8221;中有详细的说明。</p>
                        <p class=content><strong>8、 事务控制</strong></p>
                        <p class=content>事务方面对性能有影响的主要包括:事务方式的选用，事务隔离级别以及锁的选用</p>
                        <p class=content>a) 事务方式选用:如果不涉及多个事务管理器事务的话，不需要使用JTA，只有JDBC的事务控制就可以。</p>
                        <p class=content>b) 事务隔离级别:参见标准的SQL事务隔离级别</p>
                        <p class=content>c) 锁的选用:悲观锁(一般由具体的事务管理器实现)，对于长事务效率低，但安全。乐观锁(一般在应用级别实现)，如在HIBERNATE中可以定义VERSION字段，显然，如果有多个应用操作数据，且这些应用不是用同一种乐观锁机制，则乐观锁会失效。因此，针对不同的数据应有不同的策略，同前面许多情况一样，很多时候我们是在效率与安全/准确性上找一个平衡点，无论如何，优化都不是一个纯技术的问题，你应该对你的应用和业务特征有足够的了解。</p>
                        <p class=content><strong>9、 批量操作</strong></p>
                        <p class=content>即使是使用JDBC，在进行大批数据更新时，BATCH与不使用BATCH有效率上也有很大的差别。我们可以通过设置batch_size来让其支持批量操作。</p>
                        <p class=content>举个例子，要批量删除某表中的对象，如&#8220;delete Account&#8221;，打出来的语句，会发现HIBERNATE找出了所有ACCOUNT的ID，再进行删除，这主要是为了维护二级缓存，这样效率肯定高不了，在后续的版本中增加了bulk delete/update，但这也无法解决缓存的维护问题。也就是说，由于有了二级缓存的维护问题，HIBERNATE的批量操作效率并不尽如人意!</p>
                        <p class=content>从前面许多要点可以看出，很多时候我们是在效率与安全/准确性上找一个平衡点，无论如何，优化都不是一个纯技术的问题，你应该对你的应用和业务特征有足够的了解，一般的，优化方案应在架构设计期就基本确定，否则可能导致没必要的返工，致使项目延期，而作为架构师和项目经理，还要面对开发人员可能的抱怨，必竟，我们对用户需求更改的控制力不大，但技术/架构风险是应该在初期意识到并制定好相关的对策。</p>
                        <p><span class=content>还有一点要注意，应用层的缓存只是锦上添花，永远不要把它当救命稻草，应用的根基(数据库设计，算法，高效的操作语句，恰当API的选择等)才是最重要的。</span> </p>
                        </td>
                    </tr>
                </tbody>
            </table>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/19851985lili/aggbug/117633.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-05-15 15:58 <a href="http://www.blogjava.net/19851985lili/articles/117633.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HIbernate查询语言</title><link>http://www.blogjava.net/19851985lili/articles/117620.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 15 May 2007 07:26:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/117620.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/117620.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/117620.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/117620.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/117620.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 第&nbsp;14&nbsp;章&nbsp;批量处理（Batch processing）使用Hibernate将 100 000 条记录插入到数据库的一个很自然的做法可能是这样的 Session session = sessionFactory.openSession();Transaction tx = session.beginTransaction();for...&nbsp;&nbsp;<a href='http://www.blogjava.net/19851985lili/articles/117620.html'>阅读全文</a><img src ="http://www.blogjava.net/19851985lili/aggbug/117620.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-05-15 15:26 <a href="http://www.blogjava.net/19851985lili/articles/117620.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HIbernate对象共事</title><link>http://www.blogjava.net/19851985lili/articles/117612.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 15 May 2007 07:09:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/117612.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/117612.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/117612.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/117612.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/117612.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 第&nbsp;11&nbsp;章&nbsp;与对象共事Hibernate是完整的对象/关系映射解决方案，它提供了对象状态管理(state management)的功能，使开发者不再需要理会底层数据库系统的细节。 也就是说，相对于常见的JDBC/SQL持久层方案中需要管理SQL语句，Hibernate采用了更自然的面向对象的视角来持久化Java应用中的数据。 换句话说，使用H...&nbsp;&nbsp;<a href='http://www.blogjava.net/19851985lili/articles/117612.html'>阅读全文</a><img src ="http://www.blogjava.net/19851985lili/aggbug/117612.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-05-15 15:09 <a href="http://www.blogjava.net/19851985lili/articles/117612.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HIbernate关系映射</title><link>http://www.blogjava.net/19851985lili/articles/117596.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 15 May 2007 06:29:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/117596.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/117596.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/117596.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/117596.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/117596.html</trackback:ping><description><![CDATA[<div class=titlepage>
<div>
<div>
<h2 class=title><a name=associations></a>第&nbsp;8&nbsp;章&nbsp;关联关系映射</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=assoc-intro></a>8.1.&nbsp;介绍</h2>
</div>
</div>
<div></div>
</div>
<p>关联关系映射通常情况是最难配置正确的。在这个部分中，我们从单向关系映射开始，然后考虑双向关系映射，由浅至深讲述一遍典型的案例。在所有的例子中，我们都使用 <tt class=literal>Person</tt>和<tt class=literal>Address</tt>。 </p>
<p>我们根据映射关系是否涉及连接表以及多样性来划分关联类型。 </p>
<p>在传统的数据建模中，允许为Null值的外键被认为是一种不好的实践，因此我们所有的例子中都使用不允许为Null的外键。这并不是Hibernate的要求，即使你删除掉不允许为Null的约束，Hibernate映射一样可以工作的很好。 </p>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=assoc-unidirectional></a>8.2.&nbsp;单向关联（Unidirectional associations）</h2>
</div>
</div>
<div></div>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=assoc-unidirectional-m21></a>8.2.1.&nbsp;多对一(many to one)</h3>
</div>
</div>
<div></div>
</div>
<p><span class=emphasis><em>单向many-to-one关联</em></span>是最常见的单向关联关系。 </p>
<pre class=programlisting>&lt;class name="Person"&gt;
&lt;id name="id" column="personId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;many-to-one name="address"
column="addressId"
not-null="true"/&gt;
&lt;/class&gt;
&lt;class name="Address"&gt;
&lt;id name="id" column="addressId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;/class&gt;</pre>
<pre class=programlisting>create table Person ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )
</pre>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=assoc-unidirectional-121></a>8.2.2.&nbsp;一对一（one to one）</h3>
</div>
</div>
<div></div>
</div>
<p><span class=emphasis><em>基于外键关联的单向一对一关联</em></span>和<span class=emphasis><em>单向多对一关联</em></span>几乎是一样的。唯一的不同就是单向一对一关联中的外键字段具有唯一性约束。 </p>
<pre class=programlisting>&lt;class name="Person"&gt;
&lt;id name="id" column="personId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;many-to-one name="address"
column="addressId"
unique="true"
not-null="true"/&gt;
&lt;/class&gt;
&lt;class name="Address"&gt;
&lt;id name="id" column="addressId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;/class&gt;</pre>
<pre class=programlisting>create table Person ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )
</pre>
<p><span class=emphasis><em>基于主键关联的单向一对一关联</em></span>通常使用一个特定的id生成器。（请注意，在这个例子中我们掉换了关联的方向。） </p>
<pre class=programlisting>&lt;class name="Person"&gt;
&lt;id name="id" column="personId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;/class&gt;
&lt;class name="Address"&gt;
&lt;id name="id" column="personId"&gt;
&lt;generator class="foreign"&gt;
&lt;param name="property"&gt;person&lt;/param&gt;
&lt;/generator&gt;
&lt;/id&gt;
&lt;one-to-one name="person" constrained="true"/&gt;
&lt;/class&gt;</pre>
<pre class=programlisting>create table Person ( personId bigint not null primary key )
create table Address ( personId bigint not null primary key )
</pre>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=assoc-unidirectional-12m></a>8.2.3.&nbsp;一对多（one to many）</h3>
</div>
</div>
<div></div>
</div>
<p><span class=emphasis><em>基于外键关联的单向一对多关联</em></span>是一种很少见的情况，并不推荐使用。 </p>
<pre class=programlisting>&lt;class name="Person"&gt;
&lt;id name="id" column="personId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;set name="addresses"&gt;
&lt;key column="personId"
not-null="true"/&gt;
&lt;one-to-many class="Address"/&gt;
&lt;/set&gt;
&lt;/class&gt;
&lt;class name="Address"&gt;
&lt;id name="id" column="addressId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;/class&gt;</pre>
<pre class=programlisting>create table Person ( personId bigint not null primary key )
create table Address ( addressId bigint not null primary key, personId bigint not null )
</pre>
<p>我们认为对于这种关联关系最好使用连接表。 </p>
</div>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=assoc-unidirectional-join></a>8.3.&nbsp;使用连接表的单向关联（Unidirectional associations with join tables）</h2>
</div>
</div>
<div></div>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=assoc-unidirectional-join-12m></a>8.3.1.&nbsp;一对多(one to many)</h3>
</div>
</div>
<div></div>
</div>
<p><span class=emphasis><em>基于连接表的单向一对多关联</em></span> 应该优先被采用。请注意，通过指定<tt class=literal>unique="true"</tt>，我们可以把多样性从多对多改变为一对多。 </p>
<pre class=programlisting>&lt;class name="Person"&gt;
&lt;id name="id" column="personId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;set name="addresses" table="PersonAddress"&gt;
&lt;key column="personId"/&gt;
&lt;many-to-many column="addressId"
unique="true"
class="Address"/&gt;
&lt;/set&gt;
&lt;/class&gt;
&lt;class name="Address"&gt;
&lt;id name="id" column="addressId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;/class&gt;</pre>
<pre class=programlisting>create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId not null, addressId bigint not null primary key )
create table Address ( addressId bigint not null primary key )
</pre>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=assoc-unidirectional-join-m21></a>8.3.2.&nbsp;多对一（many to one）</h3>
</div>
</div>
<div></div>
</div>
<p><span class=emphasis><em>基于连接表的单向多对一关联</em></span>在关联关系可选的情况下应用也很普遍。 </p>
<pre class=programlisting>&lt;class name="Person"&gt;
&lt;id name="id" column="personId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;join table="PersonAddress"
optional="true"&gt;
&lt;key column="personId" unique="true"/&gt;
&lt;many-to-one name="address"
column="addressId"
not-null="true"/&gt;
&lt;/join&gt;
&lt;/class&gt;
&lt;class name="Address"&gt;
&lt;id name="id" column="addressId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;/class&gt;</pre>
<pre class=programlisting>create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )
</pre>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=assoc-unidirectional-join-121></a>8.3.3.&nbsp;一对一（one to one）</h3>
</div>
</div>
<div></div>
</div>
<p><span class=emphasis><em>基于连接表的单向一对一关联</em></span>非常少见，但也是可行的。 </p>
<pre class=programlisting>&lt;class name="Person"&gt;
&lt;id name="id" column="personId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;join table="PersonAddress"
optional="true"&gt;
&lt;key column="personId"
unique="true"/&gt;
&lt;many-to-one name="address"
column="addressId"
not-null="true"
unique="true"/&gt;
&lt;/join&gt;
&lt;/class&gt;
&lt;class name="Address"&gt;
&lt;id name="id" column="addressId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;/class&gt;</pre>
<pre class=programlisting>create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )
</pre>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=assoc-unidirectional-join-m2m></a>8.3.4.&nbsp;多对多（many to many）</h3>
</div>
</div>
<div></div>
</div>
<p>最后，还有 <span class=emphasis><em>单向多对多关联</em></span>. </p>
<pre class=programlisting>&lt;class name="Person"&gt;
&lt;id name="id" column="personId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;set name="addresses" table="PersonAddress"&gt;
&lt;key column="personId"/&gt;
&lt;many-to-many column="addressId"
class="Address"/&gt;
&lt;/set&gt;
&lt;/class&gt;
&lt;class name="Address"&gt;
&lt;id name="id" column="addressId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;/class&gt;</pre>
<pre class=programlisting>create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
create table Address ( addressId bigint not null primary key )
</pre>
</div>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=assoc-bidirectional></a>8.4.&nbsp;双向关联（Bidirectional associations）</h2>
</div>
</div>
<div></div>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=assoc-bidirectional-m21></a>8.4.1.&nbsp;一对多（one to many) / 多对一（many to one）</h3>
</div>
</div>
<div></div>
</div>
<p><span class=emphasis><em>双向多对一关联</em></span> 是最常见的关联关系。（这也是标准的父/子关联关系。） </p>
<pre class=programlisting>&lt;class name="Person"&gt;
&lt;id name="id" column="personId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;many-to-one name="address"
column="addressId"
not-null="true"/&gt;
&lt;/class&gt;
&lt;class name="Address"&gt;
&lt;id name="id" column="addressId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;set name="people" inverse="true"&gt;
&lt;key column="addressId"/&gt;
&lt;one-to-many class="Person"/&gt;
&lt;/set&gt;
&lt;/class&gt;</pre>
<pre class=programlisting>create table Person ( personId bigint not null primary key, addressId bigint not null )
create table Address ( addressId bigint not null primary key )
</pre>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=assoc-bidirectional-121></a>8.4.2.&nbsp;一对一（one to one）</h3>
</div>
</div>
<div></div>
</div>
<p><span class=emphasis><em>基于外键关联的双向一对一关联</em></span>也很常见。 </p>
<pre class=programlisting>&lt;class name="Person"&gt;
&lt;id name="id" column="personId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;many-to-one name="address"
column="addressId"
unique="true"
not-null="true"/&gt;
&lt;/class&gt;
&lt;class name="Address"&gt;
&lt;id name="id" column="addressId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;one-to-one name="person"
property-ref="address"/&gt;
&lt;/class&gt;</pre>
<pre class=programlisting>create table Person ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )
</pre>
<p><span class=emphasis><em>基于主键关联的一对一关联</em></span>需要使用特定的id生成器。 </p>
<pre class=programlisting>&lt;class name="Person"&gt;
&lt;id name="id" column="personId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;one-to-one name="address"/&gt;
&lt;/class&gt;
&lt;class name="Address"&gt;
&lt;id name="id" column="personId"&gt;
&lt;generator class="foreign"&gt;
&lt;param name="property"&gt;person&lt;/param&gt;
&lt;/generator&gt;
&lt;/id&gt;
&lt;one-to-one name="person"
constrained="true"/&gt;
&lt;/class&gt;</pre>
<pre class=programlisting>create table Person ( personId bigint not null primary key )
create table Address ( personId bigint not null primary key )
</pre>
</div>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=assoc-bidirectional-join></a>8.5.&nbsp;使用连接表的双向关联（Bidirectional associations with join tables）</h2>
</div>
</div>
<div></div>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=assoc-bidirectional-join-12m></a>8.5.1.&nbsp;一对多（one to many） /多对一（ many to one）</h3>
</div>
</div>
<div></div>
</div>
<p><span class=emphasis><em>基于连接表的双向一对多关联</em></span>。注意<tt class=literal>inverse="true"</tt>可以出现在关联的任意一端，即collection端或者join端。 </p>
<pre class=programlisting>&lt;class name="Person"&gt;
&lt;id name="id" column="personId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;set name="addresses"
table="PersonAddress"&gt;
&lt;key column="personId"/&gt;
&lt;many-to-many column="addressId"
unique="true"
class="Address"/&gt;
&lt;/set&gt;
&lt;/class&gt;
&lt;class name="Address"&gt;
&lt;id name="id" column="addressId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;join table="PersonAddress"
inverse="true"
optional="true"&gt;
&lt;key column="addressId"/&gt;
&lt;many-to-one name="person"
column="personId"
not-null="true"/&gt;
&lt;/join&gt;
&lt;/class&gt;</pre>
<pre class=programlisting>create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null, addressId bigint not null primary key )
create table Address ( addressId bigint not null primary key )
</pre>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=assoc-bidirectional-join-121></a>8.5.2.&nbsp;一对一（one to one）</h3>
</div>
</div>
<div></div>
</div>
<p><span class=emphasis><em>基于连接表的双向一对一关联</em></span>极为罕见，但也是可行的。 </p>
<pre class=programlisting>&lt;class name="Person"&gt;
&lt;id name="id" column="personId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;join table="PersonAddress"
optional="true"&gt;
&lt;key column="personId"
unique="true"/&gt;
&lt;many-to-one name="address"
column="addressId"
not-null="true"
unique="true"/&gt;
&lt;/join&gt;
&lt;/class&gt;
&lt;class name="Address"&gt;
&lt;id name="id" column="addressId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;join table="PersonAddress"
optional="true"
inverse="true"&gt;
&lt;key column="addressId"
unique="true"/&gt;
&lt;many-to-one name="address"
column="personId"
not-null="true"
unique="true"/&gt;
&lt;/join&gt;
&lt;/class&gt;</pre>
<pre class=programlisting>create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique )
create table Address ( addressId bigint not null primary key )
</pre>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=assoc-bidirectional-join-m2m></a>8.5.3.&nbsp;多对多（many to many）</h3>
</div>
</div>
<div></div>
</div>
<p>最后，还有 <span class=emphasis><em>双向多对多关联</em></span>. </p>
<pre class=programlisting>&lt;class name="Person"&gt;
&lt;id name="id" column="personId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;set name="addresses"&gt;
&lt;key column="personId"/&gt;
&lt;many-to-many column="addressId"
class="Address"/&gt;
&lt;/set&gt;
&lt;/class&gt;
&lt;class name="Address"&gt;
&lt;id name="id" column="addressId"&gt;
&lt;generator class="native"/&gt;
&lt;/id&gt;
&lt;set name="people" inverse="true"&gt;
&lt;key column="addressId"/&gt;
&lt;many-to-many column="personId"
class="Person"/&gt;
&lt;/set&gt;
&lt;/class&gt;</pre>
<pre class=programlisting>create table Person ( personId bigint not null primary key )
create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (personId, addressId) )
create table Address ( addressId bigint not null primary key )
</pre>
</div>
<div class=chapter lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title><a name=components></a>第&nbsp;9&nbsp;章&nbsp;组件（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>9.1.&nbsp;依赖对象（Dependent objects）</h2>
</div>
</div>
<div></div>
</div>
<p>Component是一个被包含的对象,它作为值类型被持久化，而非一个被引用的实体。&#8220;component(组件)&#8221;这一术语指的是面向对象的合成概念（而并不是系统构架层次上的组件的概念）举个例子, 你可以对人（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不支持共享引用。 换句话说，两个人可能重名，但是两个person对象应该包含两个独立的name对象，只不过是具有&#8220;同样&#8221;的值。 Component的值为空从语义学上来讲是<span class=emphasis><em>专有的(ad hoc)</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" unique="true"&gt;&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>9.2.&nbsp;在集合中出现的依赖对象</h2>
</div>
</div>
<div></div>
</div>
<p>Hibernate支持component的集合(例如: 一个元素是&#8220;姓名&#8221;这种类型的数组)。 你可以使用<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>当然，在另一方面，无法存在指向purchase的关联，因此不能实现双向关联查询。记住组建是值类型，并且不允许共享关联。单个<tt class=literal>Purchase</tt> 可以放在包含<tt class=literal>Order</tt>的集合中，但它不能同时被<tt class=literal>Item</tt>所关联。 </p>
<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>9.3.&nbsp;组件作为Map的索引（Components as Map indices ）</h2>
</div>
</div>
<div></div>
</div>
<p><tt class=literal>&lt;composite-map-key&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>9.4.&nbsp;组件作为联合标识符(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>
    <p>它必须重新实现<tt class=literal>equals()</tt>和<tt class=literal>hashCode()</tt>方法, 始终和组合关键字在数据库中的概念保持一致 </p>
    </li>
</ul>
</div>
<p><span class=emphasis><em>注意：在Hibernate3中，第二种要求并非是Hibernate强制必须的。但最好这样做。</em></span> </p>
<p>你不能使用一个<tt class=literal>IdentifierGenerator</tt>产生组合关键字。作为替代应用程序必须分配它自己的标识符。 </p>
<p>使用<tt class=literal>&lt;composite-id&gt;</tt> 标签(并且内嵌<tt class=literal>&lt;key-property&gt;</tt>元素)代替通常的<tt class=literal>&lt;id&gt;</tt>标签。 比如,<tt class=literal>OrderLine</tt>类具有一个依赖<tt class=literal>Order</tt>的(联合)主键的主键。 </p>
<pre class=programlisting>&lt;class name="OrderLine"&gt;
&lt;composite-id name="id" class="OrderLineId"&gt;
&lt;key-property name="lineId"/&gt;
&lt;key-property name="orderId"/&gt;
&lt;key-property name="customerId"/&gt;
&lt;/composite-id&gt;
&lt;property name="name"/&gt;
&lt;many-to-one name="order" class="Order"
insert="false" update="false"&gt;
&lt;column name="orderId"/&gt;
&lt;column name="customerId"/&gt;
&lt;/many-to-one&gt;
....
&lt;/class&gt;</pre>
<p>现在，任何关联到<tt class=literal>OrderLine</tt> 的外键都是复合的。在你的映射文件中，必须为其他类也这样声明。指向<tt class=literal>OrderLine</tt>的关联可能被这样映射： </p>
<pre class=programlisting>&lt;many-to-one name="orderLine" class="OrderLine"&gt;
&lt;!-- the "class" attribute is optional, as usual --&gt;
&lt;column name="lineId"/&gt;
&lt;column name="orderId"/&gt;
&lt;column name="customerId"/&gt;
&lt;/many-to-one&gt;</pre>
<p>（注意在各个地方<tt class=literal>&lt;column&gt;</tt>标签都是<tt class=literal>column</tt>属性的替代写法。） </p>
<p>指向<tt class=literal>OrderLine</tt>的<tt class=literal>多对多</tt>关联也使用联合外键: </p>
<pre class=programlisting>&lt;set name="undeliveredOrderLines"&gt;
&lt;key column name="warehouseId"/&gt;
&lt;many-to-many class="OrderLine"&gt;
&lt;column name="lineId"/&gt;
&lt;column name="orderId"/&gt;
&lt;column name="customerId"/&gt;
&lt;/many-to-many&gt;
&lt;/set&gt;</pre>
<p>在<tt class=literal>Order</tt>中, <tt class=literal>OrderLine</tt>的集合则是这样: </p>
<pre class=programlisting>&lt;set name="orderLines" inverse="true"&gt;
&lt;key&gt;
&lt;column name="orderId"/&gt;
&lt;column name="customerId"/&gt;
&lt;/key&gt;
&lt;one-to-many class="OrderLine"/&gt;
&lt;/set&gt;</pre>
<p>(与通常一样,<tt class=literal>&lt;one-to-many&gt;</tt>元素不声明任何列.) </p>
<p>假若<tt class=literal>OrderLine</tt>本身拥有一个集合,它也具有组合外键。 </p>
<pre class=programlisting>&lt;class name="OrderLine"&gt;
....
....
&lt;list name="deliveryAttempts"&gt;
&lt;key&gt;   &lt;!-- a collection inherits the composite key type --&gt;
&lt;column name="lineId"/&gt;
&lt;column name="orderId"/&gt;
&lt;column name="customerId"/&gt;
&lt;/key&gt;
&lt;list-index column="attemptId" base="1"/&gt;
&lt;composite-element class="DeliveryAttempt"&gt;
...
&lt;/composite-element&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>9.5.&nbsp;动态组件 （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="Baz" column="BAZ_ID"/&gt;
&lt;/dynamic-component&gt;</pre>
<p>从<tt class=literal>&lt;dynamic-component&gt;</tt>映射的语义上来讲，它和<tt class=literal>&lt;component&gt;</tt>是相同的。 这种映射类型的优点在于通过修改映射文件，就可以具有在部署时检测真实属性的能力.利用一个DOM解析器，是有可能在运行时刻操作映射文件的。 更好的是，你可以通过<tt class=literal>Configuration</tt>对象来访问（或者修改）Hibernate的运行时元模型。 </p>
</div>
</div>
<div class=chapter lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title><a name=inheritance></a>第&nbsp;10&nbsp;章&nbsp;继承映射(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>10.1.&nbsp; 三种策略</h2>
</div>
</div>
<div></div>
</div>
<p>Hibernate支持三种基本的继承映射策略： </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p>每个类分层结构一张表(table per class hierarchy) </p>
    <li>
    <p>每个子类一张表(table per subclass) </p>
    <li>
    <p>每个具体类一张表(table per concrete class) </p>
    </li>
</ul>
</div>
<p>此外，Hibernate还支持第四种稍有不同的多态映射策略： </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p>隐式多态(implicit polymorphism) </p>
    </li>
</ul>
</div>
<p>对于同一个继承层次内的不同分支，可以采用不同的映射策略，然后用隐式多 态来完成跨越整个层次的多态。但是在同一个<tt class=literal>&lt;class&gt;</tt>根元素 下，Hibernate不支持混合了元素<tt class=literal>&lt;subclass&gt;</tt>、 <tt class=literal>&lt;joined-subclass&gt;</tt>和<tt class=literal>&lt;union-subclass&gt;</tt> 的映射。在同一个<tt class=literal>&lt;class&gt;</tt>元素下，可以混合使用 &#8220;每个类分层结构一张表&#8221;（table per hierarchy） 和&#8220;每个子类一张表&#8221;（table per subclass） 这两种映射策略，这是通过结合元素<tt class=literal>&lt;subclass&gt;</tt>和 <tt class=literal>&lt;join&gt;</tt>来实现的（见后）。 </p>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=inheritance-tableperclass></a>10.1.1.&nbsp;每个类分层结构一张表(Table per class hierarchy)</h3>
</div>
</div>
<div></div>
</div>
<p>假设我们有接口<tt class=literal>Payment</tt>和它的几个实现类： <tt class=literal>CreditCardPayment</tt>, <tt class=literal>CashPayment</tt>, 和<tt class=literal>ChequePayment</tt>。则&#8220;每个类分层结构一张表&#8221;(Table per class hierarchy)的映射代码如下所示： </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;property name="creditCardType" column="CCTYPE"/&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>CCTYPE</tt>，不能有<tt class=literal>非空(NOT NULL)</tt>约束。 </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=inheritance-tablepersubclass></a>10.1.2.&nbsp;每个子类一张表(Table per subclass)</h3>
</div>
</div>
<div></div>
</div>
<p>对于上例中的几个类而言，采用&#8220;每个子类一张表&#8221;的映射策略，代码如下所示： </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;property name="creditCardType" column="CCTYPE"/&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>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=inheritance-tablepersubclass-discriminator></a>10.1.3.&nbsp;每个子类一张表(Table per subclass)，使用辨别标志(Discriminator)</h3>
</div>
</div>
<div></div>
</div>
<p>注意，对&#8220;每个子类一张表&#8221;的映射策略，Hibernate的实现不需要辨别字段，而其他 的对象/关系映射工具使用了一种不同于Hibernate的实现方法，该方法要求在超类 表中有一个类型辨别字段(type discriminator column)。Hibernate采用的方法更 难实现，但从关系（数据库）这点上来看，按理说它更正确。若你愿意使用带有辨别字 段的&#8220;每个子类一张表&#8221;的策略，你可以结合使用<tt class=literal>&lt;subclass&gt;</tt> 与<tt class=literal>&lt;join&gt;</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;join table="CREDIT_PAYMENT"&gt;
&lt;property name="creditCardType" column="CCTYPE"/&gt;
...
&lt;/join&gt;
&lt;/subclass&gt;
&lt;subclass name="CashPayment" discriminator-value="CASH"&gt;
&lt;join table="CASH_PAYMENT"&gt;
...
&lt;/join&gt;
&lt;/subclass&gt;
&lt;subclass name="ChequePayment" discriminator-value="CHEQUE"&gt;
&lt;join table="CHEQUE_PAYMENT" fetch="select"&gt;
...
&lt;/join&gt;
&lt;/subclass&gt;
&lt;/class&gt;</pre>
<p>可选的声明<tt class=literal>fetch="select"</tt>，是用来告诉Hibernate，在查询超类时， 不要使用外部连接(outer join)来抓取子类<tt class=literal>ChequePayment</tt>的数据。 </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=inheritance-mixing-tableperclass-tablepersubclass></a>10.1.4.&nbsp;混合使用&#8220;每个类分层结构一张表&#8221;和&#8220;每个子类一张表&#8221;</h3>
</div>
</div>
<div></div>
</div>
<p>你甚至可以采取如下方法混和使用&#8220;每个类分层结构一张表&#8221;和&#8220;每个子类一张表&#8221;这两种策略： </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;join table="CREDIT_PAYMENT"&gt;
&lt;property name="creditCardType" column="CCTYPE"/&gt;
...
&lt;/join&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>Payment</tt>的 关联是使用<tt class=literal>&lt;many-to-one&gt;</tt>进行映射的。 </p>
<pre class=programlisting>&lt;many-to-one name="payment" column="PAYMENT_ID" class="Payment"/&gt;</pre>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=inheritance-tableperconcrete></a>10.1.5.&nbsp;每个具体类一张表(Table per concrete class)</h3>
</div>
</div>
<div></div>
</div>
<p>对于&#8220;每个具体类一张表&#8221;的映射策略，可以采用两种方法。第一种方法是使用 <tt class=literal>&lt;union-subclass&gt;</tt>。 </p>
<pre class=programlisting>&lt;class name="Payment"&gt;
&lt;id name="id" type="long" column="PAYMENT_ID"&gt;
&lt;generator class="sequence"/&gt;
&lt;/id&gt;
&lt;property name="amount" column="AMOUNT"/&gt;
...
&lt;union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT"&gt;
&lt;property name="creditCardType" column="CCTYPE"/&gt;
...
&lt;/union-subclass&gt;
&lt;union-subclass name="CashPayment" table="CASH_PAYMENT"&gt;
...
&lt;/union-subclass&gt;
&lt;union-subclass name="ChequePayment" table="CHEQUE_PAYMENT"&gt;
...
&lt;/union-subclass&gt;
&lt;/class&gt;</pre>
<p>这里涉及三张表。每张表为对应类的所有属性（包括从超类继承的属性）定义相应字段。 </p>
<p>这种方式的局限在于，如果一个属性在超类中做了映射，其字段名必须与所有子类 表中定义的相同。(我们可能会在Hibernate的后续发布版本中放宽此限制。) 不允许在联合子类(union subclass)的继承层次中使用标识生成器策略(identity generator strategy), 实际上, 主键的种子(primary key seed)不得不为同一继承层次中的全部被联合子类所共用. </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=inheritance-tableperconcreate-polymorphism></a>10.1.6.&nbsp;Table per concrete class, using implicit polymorphism</h3>
</div>
<div>
<h3 class=title><a name=inheritance-tableperconcreate-polymorphism></a>10.1.6.&nbsp;Table per concrete class, using implicit polymorphism</h3>
</div>
</div>
<div></div>
</div>
<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>。同时注意 <tt class=literal>Payment</tt>的属性在每个子类中都进行了映射。如果你想避免重复， 可以考虑使用XML实体(例如：位于<tt class=literal>DOCTYPE</tt>声明内的 <tt class=literal>[ &lt;!ENTITY allproperties SYSTEM "allproperties.xml"&gt; ]</tt> 和映射中的<tt class=literal>&amp;allproperties;</tt>)。 </p>
<p>这种方法的缺陷在于，在Hibernate执行多态查询时(polymorphic queries)无法生成带 <tt class=literal>UNION</tt>的SQL语句。 </p>
<p>对于这种映射策略而言，通常用<tt class=literal>&lt;any&gt;</tt>来实现到 <tt class=literal>Payment</tt>的多态关联映射。 </p>
<pre class=programlisting>&lt;any name="payment" meta-type="string" id-type="long"&gt;
&lt;meta-value value="CREDIT" class="CreditCardPayment"/&gt;
&lt;meta-value value="CASH" class="CashPayment"/&gt;
&lt;meta-value value="CHEQUE" class="ChequePayment"/&gt;
&lt;column name="PAYMENT_CLASS"/&gt;
&lt;column name="PAYMENT_ID"/&gt;
&lt;/any&gt;</pre>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=inheritace-mixingpolymorphism></a>10.1.7.&nbsp;隐式多态和其他继承映射混合使用</h3>
</div>
</div>
<div></div>
</div>
<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>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=inheritance-limitations></a>10.2.&nbsp;限制</h2>
</div>
</div>
<div></div>
</div>
<p>对&#8220;每个具体类映射一张表&#8221;（table per concrete-class）的映射策略而言，隐式多态的 方式有一定的限制。而<tt class=literal>&lt;union-subclass&gt;</tt>映射的限制则没有那 么严格。 </p>
<p>下面表格中列出了在Hibernte中&#8220;每个具体类一张表&#8221;的策略和隐式多态的限制。 </p>
<div class=table><a name=d0e8645></a>
<p class=title><strong>表&nbsp;10.1.&nbsp;继承映射特性(Features of inheritance mappings) </strong></p>
<table summary="继承映射特性(Features of inheritance mappings)&#9;&#9;&#9;" 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>每个具体类一张表(union-subclass)</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> (仅对于<tt class=literal>inverse="true"</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><tt class=literal>s.createCriteria(Payment.class).add( Restrictions.idEq(id) ).uniqueResult()</tt></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>
</div>
</div>
<img src ="http://www.blogjava.net/19851985lili/aggbug/117596.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-05-15 14:29 <a href="http://www.blogjava.net/19851985lili/articles/117596.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HibenateMinute(三) </title><link>http://www.blogjava.net/19851985lili/articles/117585.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 15 May 2007 06:07:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/117585.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/117585.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/117585.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/117585.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/117585.html</trackback:ping><description><![CDATA[&nbsp;
<p><strong><span>hiberate</span></strong><strong><span>缓</span></strong><strong><span>存</span></strong><strong><span>&nbsp;</span></strong><strong><span>一般而言，</span><span>ORM</span></strong><strong><span>的数据</span></strong><strong><span>缓</span></strong><strong><span>存</span></strong><strong><span>应</span></strong><strong><span>包含如下几个</span></strong><strong><span>层</span></strong><strong><span>次</span></strong><span>：</span></p>
<p><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>事</span><span>务级缓</span><span>存（</span><span>Transcation Layer Cache</span><span>）</span></p>
<p><span><span>2.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>应</span><span>用</span><span>级</span><span>/</span><span>进</span><span>程</span><span>级缓</span><span>存（</span><span>Application/Process Layer Cache</span><span>）</span></p>
<p><span><span>3.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span>&nbsp;<span>分布式</span><span>缓</span><span>存（</span><span>Cluster Layer Cache</span><span>）</span></p>
<p><span>Hibernate</span><span>数据</span><span>缓</span><span>存（</span><span>Cache</span><span>）分</span><span>为</span><span>两个</span><span>层</span><span>次，以</span><span>Hibernate</span><span>语义</span><span>加以区分，</span></p>
<p><span>可分</span><span>为</span><span>：</span></p>
<p><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>内部</span><span>缓</span><span>存（</span><span>Session Level</span><span>，也称</span><span>为</span><span>一</span><span>级缓</span><span>存）</span></p>
<p><span><span>2.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>二</span><span>级缓</span><span>存（</span><span>SessionFactory Level</span><span>，也称</span><span>为</span><span>二</span><span>级缓</span><span>存）</span></p>
<p><span>Hibernate</span><span>中，</span><span>缓</span><span>存将在以下情况中</span><span>发挥</span><span>作用：</span></p>
<p><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>通</span><span>过</span><span>id[</span><span>主</span><span>键</span><span>]</span><span>加</span><span>载</span><span>数据</span><span>时</span><span>每个实体</span><span>唯一的</span><span>OID</span></p>
<p><span><span>2.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>延</span><span>迟</span><span>加</span><span>载</span></p>
<p><strong>&nbsp;</strong></p>
<p><span>@ </span><strong><span>Cache</span></strong><strong><span>缓存</span></strong><strong><span>:</span></strong></p>
<p><span><span>1.<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>Session level</span><span> (</span><span>一级缓存</span><span>):</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span>主要作用于</span></strong><span>:</span><span>主键获得的数据</span><span>, </span><span>延迟初始化</span><span>(</span><span>Lazy Initialization</span><span>)</span><span>起作用</span><span>.</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><span>状态依赖于</span></strong><span>:</span><span>Session</span><span>的建立而建立</span><span>(</span><span>销毁而销毁</span><span>).// </span><strong><span>Session</span></strong><strong><span>是个</span></strong><strong><span>Map</span></strong><strong><span>容器</span></strong><strong><span>!</span></strong></p>
<p><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;</span></strong><strong><span>清除</span></strong><strong><span>Session</span></strong><strong><span>对象</span></strong><strong><span>:</span></strong><span> </span><span>&nbsp;</span><span>Session</span><span>.</span><span>Save</span><span>()</span><span>也是交给</span><span>Session level</span><span>来管理</span><span>,</span><span>很多的时候会发生</span><span>OutOfMemoryError</span><span>异常</span><span>,</span><span>所以要及时发送给数据库</span><span>session.flush()</span><span>,</span><span>清除</span><span>session.clear()</span><span>或</span><span>session.evict(user1);</span></p>
<p><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></strong><strong><span>在</span></strong><strong><span>SQL Server</span></strong><strong><span>、</span></strong><strong><span>Oracle</span></strong><strong><span>,</span></strong><strong><span> Hibernat</span></strong><strong><span>设</span></strong><strong><span>定属性</span></strong><strong><span>hibernate.jdbc.batch_size</span></strong><strong><span>多少数据发送</span></strong><strong></strong></p>
<p><span>&nbsp;</span><span>&lt;hibernate-configuration&gt;</span><span> </span><span>&lt;session-factory&gt;</span></p>
<p><span>&lt;property</span><span> </span><span>name="hibernate.jdbc.batch_size"&gt;100</span></p>
<p><span>&lt;/property&gt;&nbsp;</span><strong><span>//</span></strong><strong><span> MySQL</span></strong><strong><span>是不支持的</span></strong><strong><span>,</span></strong></p>
<p><span>&lt;/session-factory&gt;</span></p>
<p><span>&lt;hibernate-configuration&gt;</span></p>
<p>&nbsp;</p>
<p><span><span>2.<span>&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><span>SessionFactory level</span><span>(</span><span>二</span><span>级缓</span><span>存</span><span>)</span></p>
<p><span>　　</span><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>　</span><span>二</span><span>级缓</span><span>存是</span><span>SessionFactory</span><span>级别</span><span>的全局</span><span>缓</span><span>存</span><span>,</span><span> </span><span>是</span><span>进</span><span>程范</span><span>围</span><span>或者集群范</span><span>围</span><span>的</span><span>缓</span><span>存</span><span>,</span><span> </span><span>存放的</span><span>对</span><span>象的松散数据</span><span>,</span><span>可能出</span><span>现</span><span>并</span><span>发问题</span><span>,</span><span> </span><span>需要采用适当的并</span><span>发访问</span><span>策略，</span><span>该</span><span>策略</span><span>为</span><span>被</span><span>缓</span><span>存的数据提供了事</span><span>务</span><span>隔离</span><span>级别</span><span>。</span><span>缓</span><span>存适配器用于把具体的</span><span>缓</span><span>存</span><span>实现软</span><span>件与</span><span>Hibernate</span><span>集成。第二</span><span>级缓</span><span>存是可</span><span>选</span><span>的，可以在</span><span>每</span><span>个</span><span>类</span><span>或</span><span>每</span><span>个集合的粒度上配置第二</span><span>级缓</span><span>存。</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>可以使用不同的</span><span>缓</span><span>存</span><span>类库</span><span>，比如<span>ehcache</span>、<span>oscache</span>等，需要</span><span>设</span><span>置<span>hibernate.cache.provider_class</span>，之后，需要在映射文件中指定各个映射</span><span>实</span><span>体<span>(</span>以及<span>collection)</span>的</span><span>缓</span><span>存同</span><span>步</span><span>策略。<span>Hibernate</span>提供了一下<span>4</span></span><span>种</span><span>内置的</span><span>缓</span><span>存同</span><span>步</span><span>策略：<span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1. read-only<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>只</span><span>读</span><span>。</span><span>对</span><span>于不会</span><span>发</span><span>生改</span><span>变</span><span>的数据，可使用只</span><span>读</span><span>型</span><span>缓</span><span>存。<span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2. nonstrict-read-write<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>如果程序</span><span>对</span><span>并</span><span>发访问</span><span>下的数据同</span><span>步</span><span>要求不是非常</span><span>严</span><span>格，且数据更新操作</span><span>频</span><span>率</span><span>较</span><span>低，可以采用本</span><span>选项</span><span>，</span><span>获</span><span>得</span><span>较</span><span>好的性能。<span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3. read-write<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span><span>严</span><span>格可</span><span>读</span><span>写</span><span>缓</span><span>存。基于</span><span>时间</span><span>戳判定机制，</span><span>实现</span><span>了&#8220;<span>read committed</span>&#8221;事</span><span>务</span><span>隔离等</span><span>级</span><span>。可用于</span><span>对</span><span>数据同</span><span>步</span><span>要求</span><span>严</span><span>格的</span><span>情况，但不支持分布式缓存。这也是实际应用中使用最多的同步策略。</span><span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4. transactional<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>事务型缓存，必须运行在</span><span>JTA</span><span>事务环境中。</span></p>
<p><span>如果使用查询缓存，加上</span><span>hibernate.cache.use_query_cache=true</span><span>，只有当经常使用同样的参数进行查询时，这才会有些用处。该设置将会创建两个缓存区域</span><span> - </span><span>一个用于保存查询结果集</span><span>(</span><tt><span>org.hibernate.cache.StandardQueryCache</span></tt><span>)</span><span>；</span><span> </span><span>另一个则用于保存最近查询的一系列表的时间戳</span><span>(</span><tt><span>org.hibernate.cache.UpdateTimestampsCache</span></tt><span>)</span><span>。</span><span> </span><span>请注意：在查询缓存中，它并不缓存结果集中所包含的实体的确切状态；它只缓存这些实体的标识符属性的值、以及各值类型的结果。</span><span> </span><span>所以查询缓存通常会和二级缓存一起使用。</span><span> </span><span>绝大多数的查询并不能从查询缓存中受益，所以</span><span>Hibernate</span><span>默认是不进行查询缓存的。如若需要进行缓存，请调用</span><span> </span><tt><span>Query.setCacheable(true)</span></tt><span>方法。这个调用会让查询在执行过程中时先从缓存中查找结果，</span><span> </span><span>并将自己的结果集放到缓存中去。</span></p>
<p><strong><span>Hibernate</span></strong><strong><span>的二</span></strong><strong><span>级缓</span></strong><strong><span>存策略的一般</span></strong><strong><span>过</span></strong><strong><span>程如下：</span></strong><strong></strong></p>
<p><strong>&nbsp;</strong></p>
<p><span>1) </span><span>条件</span><span>查询</span><span>的</span><span>时</span><span>候，</span><span>总</span><span>是</span><span>发</span><span>出一条</span><span>select * from table_name where </span><span>&#8230;</span><span>. </span><span>（</span><span>选择</span><span>所有字段）</span><span>这样</span><span>的</span><span>SQL</span><span>语</span><span>句</span><span>查询</span><span>数据</span><span>库</span><span>，一次</span><span>获</span><span>得所有的数据</span><span>对</span><span>象。</span></p>
<p><span>2) </span><span>把</span><span>获</span><span>得的所有数据</span><span>对</span><span>象根据</span><span>ID</span><span>放入到第二</span><span>级缓</span><span>存中。</span><span> </span></p>
<p><span>3) </span><span>当</span><span>Hibernate</span><span>根据</span><span>ID</span><span>访问</span><span>数据</span><span>对</span><span>象的</span><span>时</span><span>候，首先从</span><span>Session</span><span>一</span><span>级缓</span><span>存中</span><span>查</span><span>；</span><span>查</span><span>不到，如果配置了二</span><span>级缓</span><span>存，那</span><span>么</span><span>从二</span><span>级缓</span><span>存中</span><span>查</span><span>；</span><span>查</span><span>不到，再</span><span>查询</span><span>数据</span><span>库</span><span>，把</span><span>结</span><span>果按照</span><span>ID</span><span>放入到</span><span>缓</span><span>存。</span><span> </span></p>
<p><span>4) </span><span>删</span><span>除、更新、增加数据的</span><span>时</span><span>候，同</span><span>时</span><span>更新</span><span>缓</span><span>存。</span></p>
<p><span>　　</span><span>Hibernate</span><span>的二</span><span>级缓</span><span>存策略，是</span><span>针对</span><span>于</span><span>ID</span><span>查询</span><span>的</span><span>缓</span><span>存策略，</span><span>对</span><span>于条件</span><span>查询则</span><span>毫无作用。</span><span>为</span><span>此，</span><span>Hibernate</span><span>提供了</span><span>针对</span><span>条件</span><span>查询</span><span>的</span><span>Query</span><span>缓</span><span>存。</span></p>
<p>&nbsp;</p>
<p><strong><span>Hibernate</span></strong><strong><span>的</span></strong><strong><span>Query</span></strong><strong><span>缓</span></strong><strong><span>存策略的</span></strong><strong><span>过</span></strong><strong><span>程如下：</span></strong><strong></strong></p>
<p><strong>&nbsp;</strong></p>
<p><strong><span>1) Hibernate</span></strong><strong><span>首先根据</span></strong><strong><span>这</span></strong><strong><span>些信息</span></strong><strong><span>组</span></strong><strong><span>成一个</span></strong><strong><span>Query Key</span></strong><strong><span>，</span></strong><strong><span>Query Key</span></strong><strong><span>包括条件</span></strong><strong><span>查询</span></strong><strong><span>的</span></strong><strong><span>请</span></strong><strong><span>求一般信息：</span></strong><strong><span>SQL, SQL</span></strong><strong><span>需要的参数，</span></strong><strong><span>记录</span></strong><strong><span>范</span></strong><strong><span>围</span></strong><strong><span>（起始位置</span></strong><strong><span>rowStart</span></strong><strong><span>，最大</span></strong><strong><span>记录</span></strong><strong><span>个数</span></strong><strong><span>maxRows)</span></strong><strong><span>，等。</span></strong><strong><span> </span></strong></p>
<p><strong><span>2) Hibernate</span></strong><strong><span>根据</span></strong><strong><span>这</span></strong><strong><span>个</span></strong><strong><span>Query Key</span></strong><strong><span>到<span>Query</span></span></strong><strong><span>缓</span></strong><strong><span>存中</span></strong><strong><span>查</span></strong><strong><span>找</span></strong><strong><span>对应</span></strong><strong><span>的</span></strong><strong><span>结</span></strong><strong><span>果列表。如果存在，那</span></strong><strong><span>么</span></strong><strong><span>返回</span></strong><strong><span>这</span></strong><strong><span>个</span></strong><strong><span>结</span></strong><strong><span>果列表；如果不存在，</span></strong><strong><span>查询</span></strong><strong><span>数据</span></strong><strong><span>库</span></strong><strong><span>，</span></strong><strong><span>获</span></strong><strong><span>取</span></strong><strong><span>结</span></strong><strong><span>果列表，把整个</span></strong><strong><span>结</span></strong><strong><span>果列表根据</span></strong><strong><span>Query Key</span></strong><strong><span>放入到<span>Query</span></span></strong><strong><span>缓</span></strong><strong><span>存中。</span></strong><strong><span> </span></strong></p>
<p><strong><span>3) Query Key</span></strong><strong><span>中的<span>SQL</span></span></strong><strong><span>涉</span></strong><strong><span>及到一些表名，如果</span></strong><strong><span>这</span></strong><strong><span>些表的任何数据</span></strong><strong><span>发</span></strong><strong><span>生修改、</span></strong><strong><span>删</span></strong><strong><span>除、增加等操作，</span></strong><strong><span>这</span></strong><strong><span>些相</span></strong><strong><span>关</span></strong><strong><span>的</span></strong><strong><span>Query Key</span></strong><strong><span>都要从</span></strong><strong><span>缓</span></strong><strong><span>存中清空。</span></strong><strong></strong></p>
<p><strong>&nbsp;</strong></p>
<p><strong><span>什</span></strong><strong><span>么样</span></strong><strong><span>的数据适合存放到第二</span></strong><strong><span>级缓</span></strong><strong><span>存中？</span></strong><strong></strong></p>
<p><strong><span>1 </span></strong><strong><span>很少被修改的数据</span></strong><strong></strong></p>
<p><strong><span>2 </span></strong><strong><span>不是很重要的数据，允</span></strong><strong><span>许</span></strong><strong><span>出</span></strong><strong><span>现</span></strong><strong><span>偶</span></strong><strong><span>尔</span></strong><strong><span>并</span></strong><strong><span>发</span></strong><strong><span>的数据</span></strong><strong></strong></p>
<p><strong><span>3 </span></strong><strong><span>不会被并</span></strong><strong><span>发访问</span></strong><strong><span>的数据</span></strong><strong></strong></p>
<p><strong><span>4 </span></strong><strong><span>参考数据</span></strong><strong></strong></p>
<p><strong><span>不适合存放到第二</span></strong><strong><span>级缓</span></strong><strong><span>存的数据？</span></strong><strong></strong></p>
<p><strong><span>1 </span></strong><strong><span>经</span></strong><strong><span>常被修改的数据</span></strong><strong></strong></p>
<p><strong><span>2 </span></strong><strong><span>财务</span></strong><strong><span>数据，</span></strong><strong><span>绝对</span></strong><strong><span>不允</span></strong><strong><span>许</span></strong><strong><span>出</span></strong><strong><span>现</span></strong><strong><span>并</span></strong><strong><span>发</span></strong><strong></strong></p>
<p><strong><span>3 </span></strong><strong><span>与其他</span></strong><strong><span>应</span></strong><strong><span>用共享的数据</span></strong><strong></strong></p>
<p><strong><span>无</span></strong><strong><span>论</span></strong><strong><span>何</span></strong><strong><span>时</span></strong><strong><span>，当</span></strong><strong><span>给</span></strong><strong><span>save()</span></strong><strong><span>、<span>update()</span>或<span> saveOrUpdate()</span>方法</span></strong><strong><span>传递</span></strong><strong><span>一个</span></strong><strong><span>对</span></strong><strong><span>象</span></strong><strong><span>时</span></strong><strong><span>，或使用<span>load()</span>、<span> get()</span>、<span>list()</span>、<span>iterate() </span>或<span>scroll()</span>方法</span></strong><strong><span>获</span></strong><strong><span>得一个</span></strong><strong><span>对</span></strong><strong><span>象</span></strong><strong><span>时</span></strong><strong><span>, </span></strong><strong><span>该对</span></strong><strong><span>象都将被加入到<span>Session</span>的内部</span></strong><strong><span>缓</span></strong><strong><span>存中。 </span></strong></p>
<p><strong><span>当随后</span></strong><strong><span>flush()</span></strong><strong><span>方法被</span></strong><strong><span>调</span></strong><strong><span>用</span></strong><strong><span>时</span></strong><strong><span>，</span></strong><strong><span>对</span></strong><strong><span>象的状</span></strong><strong><span>态</span></strong><strong><span>会和数据</span></strong><strong><span>库</span></strong><strong><span>取得同</span></strong><strong><span>步</span></strong><strong><span>。 如果你不希望此同</span></strong><strong><span>步</span></strong><strong><span>操作</span></strong><strong><span>发</span></strong><strong><span>生，或者你正</span></strong><strong><span>处</span></strong><strong><span>理大量</span></strong><strong><span>对</span></strong><strong><span>象、需要</span></strong><strong><span>对</span></strong><strong><span>有效管理内存</span></strong><strong><span>时</span></strong><strong><span>，你可以</span></strong><strong><span>调</span></strong><strong><span>用</span></strong><strong><span>evict() </span></strong><strong><span>方法，从一</span></strong><strong><span>级缓</span></strong><strong><span>存中去掉</span></strong><strong><span>这</span></strong><strong><span>些</span></strong><strong><span>对</span></strong><strong><span>象及其集合。如若要把所有的</span></strong><strong><span>对</span></strong><strong><span>象从</span></strong><strong><span>session</span></strong><strong><span>缓</span></strong><strong><span>存中</span></strong><strong><span>彻</span></strong><strong><span>底清除，</span></strong><strong><span>则</span></strong><strong><span>需要</span></strong><strong><span>调</span></strong><strong><span>用</span></strong><strong><span>Session.clear()</span></strong><strong><span>，不</span></strong><strong><span>过</span></strong><strong><span>最好先</span></strong><strong><span>Session.flush()</span></strong></p>
<p><strong><span>SessionFactory</span></strong><strong><span>也提供了移除</span></strong><strong><span>缓</span></strong><strong><span>存的方法，</span></strong><strong><span>这</span></strong><strong><span>些方法是：</span></strong><strong><span> <br>sessionFactory.evict(Cat.class, catId); //evict a particular Cat<br>sessionFactory.evict(Cat.class);&nbsp; //evict all Cats<br>sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens<br>sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections</span></strong></p>
<p><strong>&nbsp;</strong></p>
<p><strong><span>对</span></strong><strong><span>于事物管理的确定</span></strong><strong><span>:</span></strong></p>
<p><strong><span>&nbsp;</span></strong><span>hibernate.cfg.xml </span><span>:</span></p>
<p><span><span>&nbsp;&nbsp; </span></span><span>&lt;hibernate-configuration&gt; </span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>&lt;session-factory&gt; </span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>....</span></p>
<p><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;!-- </span></strong><strong><span>設定事務管理的工廠類</span><span> --&gt; <br><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&lt;property name="hibernate.transaction.factory_class"&gt; </span></strong><strong></strong></p>
<p><strong><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>org.hibernate.transaction.JDBCTransactionFactory &nbsp;&lt;/property&gt; </span></strong></p>
<p><span>&lt;/hibernate-configuration&gt;</span><strong></strong></p>
<p align=left><span>try { </span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; session = sessionFactory.openSession(); &nbsp;</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; Transaction tx = session.beginTransaction(); </span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; .... </span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; tx.commit(); &nbsp;<strong>// </strong></span><strong><span>必須</span></strong><strong><span>commit</span></strong><strong><span>才會更新資料庫</span></strong><strong></strong></p>
<p align=left><span>} catch(HibernateException e) { </span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; tx.rollback(); </span></p>
<p align=left><span>}</span></p>
<p><strong><span>Postil: </span></strong><span>对于</span><span>MySQL</span><span>处理机制要建立事物表类型的</span><strong></strong></p>
<p><strong><span>类型的对照表</span></strong><strong><span>:</span></strong></p>
<table cellPadding=0 width="100%" border=1>
    <tbody>
        <tr>
            <td>
            <p align=left><span>Java</span><span> </span></p>
            </td>
            <td>
            <p align=left><span>Hibernate</span><span> </span></p>
            </td>
            <td>
            <p align=left><span>SQL</span><span> </span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>byte</span><span>、</span><span>java.lang.Byte</span></p>
            </td>
            <td>
            <p align=left><span>byte</span></p>
            </td>
            <td>
            <p align=left><span>TINYINT</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>short</span><span>、</span><span>java.lang.Short</span></p>
            </td>
            <td>
            <p align=left><span>short</span></p>
            </td>
            <td>
            <p align=left><span>SMALLINT</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>int</span><span>、</span><span>java.lang.Integer</span></p>
            </td>
            <td>
            <p align=left><span>integer</span></p>
            </td>
            <td>
            <p align=left><span>INGEGER</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>long</span><span>、</span><span>java.lang.Long</span></p>
            </td>
            <td>
            <p align=left><span>long</span></p>
            </td>
            <td>
            <p align=left><span>BIGINT</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>float</span><span>、</span><span>java.lang.Float</span></p>
            </td>
            <td>
            <p align=left><span>float</span></p>
            </td>
            <td>
            <p align=left><span>FLOAT</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>double</span><span>、</span><span>java.lang.Double</span></p>
            </td>
            <td>
            <p align=left><span>double</span></p>
            </td>
            <td>
            <p align=left><span>DOUBLE</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>java.math.BigDecimal</span></p>
            </td>
            <td>
            <p align=left><span>big_decimal</span></p>
            </td>
            <td>
            <p align=left><span>NUMERIC</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>char</span><span>、</span><span>java.lang.Character</span></p>
            </td>
            <td>
            <p align=left><span>character</span></p>
            </td>
            <td>
            <p align=left><span>CHAR(1)</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>boolean</span><span>、</span><span>java.lang.Boolean</span></p>
            </td>
            <td>
            <p align=left><span>boolean</span></p>
            </td>
            <td>
            <p align=left><span>BIT</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>java.lang.String</span></p>
            </td>
            <td>
            <p align=left><span>string</span></p>
            </td>
            <td>
            <p align=left><span>VARCHAR</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>boolean</span><span>、</span><span>java.lang.Boolean</span></p>
            </td>
            <td>
            <p align=left><span>yes_no</span></p>
            </td>
            <td>
            <p align=left><span>CHAR(1)('Y'</span><span>或</span><span>'N')</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>boolean</span><span>、</span><span>java.lang.Boolean</span></p>
            </td>
            <td>
            <p align=left><span>true_false</span></p>
            </td>
            <td>
            <p align=left><span>CHAR(1)('Y'</span><span>或</span><span>'N')</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>java.util.Date</span><span>、</span><span>java.sql.Date</span></p>
            </td>
            <td>
            <p align=left><span>date</span></p>
            </td>
            <td>
            <p align=left><span>DATE</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>java.util.Date</span><span>、</span><span>java.sql.Time</span></p>
            </td>
            <td>
            <p align=left><span>time</span></p>
            </td>
            <td>
            <p align=left><span>TIME</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>java.util.Date</span><span>、</span><span>java.sql.Timestamp</span></p>
            </td>
            <td>
            <p align=left><span>timestamp</span></p>
            </td>
            <td>
            <p align=left><span>TIMESTAMP</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>java.util.Calendar</span></p>
            </td>
            <td>
            <p align=left><span>calendar</span></p>
            </td>
            <td>
            <p align=left><span>TIMESTAMP</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>java.util.Calendar</span></p>
            </td>
            <td>
            <p align=left><span>calendar_date</span></p>
            </td>
            <td>
            <p align=left><span>DATE</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>byte[]</span></p>
            </td>
            <td>
            <p align=left><span>binary</span></p>
            </td>
            <td>
            <p align=left><span>VARBINARY</span><span>、</span><span>BLOB</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>java.lang.String</span></p>
            </td>
            <td>
            <p align=left><span>text</span></p>
            </td>
            <td>
            <p align=left><span>CLOB</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>java.io.Serializable</span></p>
            </td>
            <td>
            <p align=left><span>serializable</span></p>
            </td>
            <td>
            <p align=left><span>VARBINARY</span><span>、</span><span>BLOB</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>java.sql.Clob</span></p>
            </td>
            <td>
            <p align=left><span>clob</span></p>
            </td>
            <td>
            <p align=left><span>CLOB</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>java.sql.Blob</span></p>
            </td>
            <td>
            <p align=left><span>blob</span></p>
            </td>
            <td>
            <p align=left><span>BLOB</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>java.lang.Class</span></p>
            </td>
            <td>
            <p align=left><span>class</span></p>
            </td>
            <td>
            <p align=left><span>VARCHAR</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>java.util.Locale</span></p>
            </td>
            <td>
            <p align=left><span>locale</span></p>
            </td>
            <td>
            <p align=left><span>VARCHAR</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>java.util.TimeZone</span></p>
            </td>
            <td>
            <p align=left><span>timezone</span></p>
            </td>
            <td>
            <p align=left><span>VARCHAR</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>java.util.Currency</span></p>
            </td>
            <td>
            <p align=left><span>currency</span></p>
            </td>
            <td>
            <p align=left><span>VARCHAR</span></p>
            </td>
        </tr>
    </tbody>
</table>
<img src ="http://www.blogjava.net/19851985lili/aggbug/117585.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-05-15 14:07 <a href="http://www.blogjava.net/19851985lili/articles/117585.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HibenateMinute(二)</title><link>http://www.blogjava.net/19851985lili/articles/117584.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 15 May 2007 06:05:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/117584.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/117584.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/117584.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/117584.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/117584.html</trackback:ping><description><![CDATA[&nbsp;
<p><strong><span>Criteria</span></strong><strong><span>:</span></strong></p>
<p align=left><span>Criteria criteria = session.createCriteria(User.class);</span></p>
<p align=left><strong><span>1)</span></strong><span>criteria.add(Restrictions.gt("age", new Integer(20)));</span></p>
<p align=left><strong><span>2)</span></strong><span>criteria.add(Restrictions.lt("age", new Integer(40)));</span></p>
<p align=left><strong><span>3)</span></strong><span>criteria.add(Restrictions.or(Restrictions.eq("age", new Integer(20)), Restrictions.isNull("age")));</span></p>
<p align=left><code><strong><span>crit.add(Restrictions.ilike(</span></strong></code><code><strong><span>"name"</span></strong></code><code><strong><span>,</span></strong></code><code><strong><span>"1"</span></strong></code><code><strong><span>,&nbsp;MatchMode.END));</span></strong></code><code><strong></strong></code></p>
<p align=left><code><strong><span>//</span></strong></code><span> //</span><span> <span>ilike</span></span><span>的</span><span>i</span><span>即</span><span>ignore</span><span>之意</span><span>,</span><span>所以</span><span>这</span><span>里</span><span>查询</span><span>出</span><span>englishName"Optima?XL?100K?Ultracentrifuge"</span><span>（忽略大小写）的</span><span>记录</span><strong></strong></p>
<p align=left><strong><span>4)</span></strong><span>criteria.add(Restrictions.sqlRestriction("{alias}.name LIKE (?)", "cater%", Hibernate.STRING));</span></p>
<p align=left><strong><span>5)</span></strong><strong><span> </span></strong><span>Integer[] ages = {new Integer(20), new Integer(40)};</span></p>
<p align=left><span>Type[] types = {Hibernate.INTEGER, Hibernate.INTEGER};</span></p>
<p align=left><span>criteria.add(Restrictions.sqlRestriction("{alias}.age BETWEEN (?) AND (?)", ages, types));</span></p>
<p align=left>&nbsp;</p>
<p align=left><strong><span>6)</span></strong><strong><span> </span></strong><span>criteria.setFirstResult(51); </span></p>
<p align=left><span>criteria.setMaxResult(50);</span></p>
<p align=left><span>&nbsp;<strong>&nbsp;7)</strong></span><strong><span> </span></strong><strong><span>统计表</span></strong><span>rowCount()</span><span>、</span><span>count()</span><span>、</span><span>max()</span><span>、</span><span>min()</span><span>、</span><span>countDistinct()</span><strong></strong></p>
<p align=left><span>criteria.setProjection(Projections.avg("age"));</span></p>
<p align=left><span>&nbsp;<strong>&nbsp;8)</strong></span><strong><span>分组</span></strong><span>20,20,25,30 </span><span><span>&#224;</span></span><span> 20.25.30</span></p>
<p align=left><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span>&nbsp;</span><span>criteria.setProjection(Projections.groupProperty("age"));</span><span> </span></p>
<p align=left><span>&nbsp;<strong>9)</strong></span><strong><span>结合统计分组</span></strong><strong></strong></p>
<p align=left><strong><span><span>&nbsp;&nbsp; </span></span></strong><span>ProjectionList projectionList = Projections.projectionList();</span></p>
<p align=left><span>projectionList.add(Projections.groupProperty("age"));</span></p>
<p align=left><span>projectionList.add(Projections.rowCount());</span></p>
<p align=left><span>Criteria criteria = session.createCriteria(User.class);</span></p>
<p align=left><span>criteria.setProjection(projectionList);</span></p>
<p align=left><strong><span>10)</span></strong><strong><span> </span></strong><strong><span>Query Criteria Id: data type Long</span></strong><strong></strong></p>
<p align=left><span>projectionList.add(</span><code><span>crit.add(&nbsp;Expression.idEq(&nbsp;</span></code><code><span>11111L</span></code><code><span>)&nbsp;);</span></code><code></code></p>
<p align=left><strong><span>11)</span></strong><strong><span> </span></strong><strong><span>Query Criteria Id: Not Equal</span></strong><code><strong></strong></code></p>
<p align=left><code>&nbsp;</code><code><span>crit.add(&nbsp;Expression.ne(&nbsp;</span></code><code><span>"name"</span></code><code><span>,&nbsp;</span></code><code><span>"noName"&nbsp;</span></code><code><span>)&nbsp;);</span></code><code><span>)</span></code></p>
<p align=left><code><strong><span>12)</span></strong></code><code><span>crit.setProjection(Projections.rowCount());</span></code></p>
<p align=left><code><strong><span>13</span></strong></code><code><strong><span>）</span></strong></code><code><strong><span>这</span></strong></code><code><strong><span>是</span></strong></code><code><strong><span>显</span></strong></code><code><strong><span>示不重</span></strong></code><code><strong><span>复记录</span></strong></code><code><strong></strong></code></p>
<p align=left><code><span>criteria.setResultTransformer(criteria.DISTINCT_ROOT_ENTITY);</span></code></p>
<p align=left><span>List users = criteria.list();</span></p>
<p align=left><span>Restrictions</span><span>的幾個常用限定</span><span>查</span><span>詢方法如下表所示：</span></p>
<table cellPadding=0 width="100%" border=1>
    <tbody>
        <tr>
            <td>
            <p align=left><span>方法</span></p>
            </td>
            <td>
            <p align=left><span>說</span><span>明</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>Restrictions.eq</span></p>
            </td>
            <td>
            <p align=left><span>等於</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>Restrictions.allEq</span></p>
            </td>
            <td>
            <p align=left><span>使用</span><span>Map</span><span>，使用</span><span>key/value</span><span>進行多個等於的比對</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>Restrictions.gt</span></p>
            </td>
            <td>
            <p align=left><span>大於</span><span> &gt;</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>Restrictions.ge</span></p>
            </td>
            <td>
            <p align=left><span>大於等於</span><span> &gt;=</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>Restrictions.lt</span></p>
            </td>
            <td>
            <p align=left><span>小於</span><span> &lt;</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>Restrictions.le</span></p>
            </td>
            <td>
            <p align=left><span>小於等於</span><span> &lt;=</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>Restrictions.between</span></p>
            </td>
            <td>
            <p align=left><span>對應</span><span>SQL</span><span>的</span><span>BETWEEN</span><span>子句</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>Restrictions.like</span></p>
            </td>
            <td>
            <p align=left><span>對應</span><span>SQL</span><span>的</span><span>LIKE</span><span>子句</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>Restrictions.in</span></p>
            </td>
            <td>
            <p align=left><span>對應</span><span>SQL</span><span>的</span><span>in</span><span>子句</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>Restrictions.and</span></p>
            </td>
            <td>
            <p align=left><span>and</span><span>關係</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>Restrictions.or</span></p>
            </td>
            <td>
            <p align=left><span>or</span><span>關係</span></p>
            </td>
        </tr>
        <tr>
            <td>
            <p align=left><span>Restrictions.sqlRestriction</span></p>
            </td>
            <td>
            <p align=left><span>SQL</span><span>限定</span><span>查</span><span>詢</span></p>
            </td>
        </tr>
    </tbody>
</table>
<p align=left><strong><span>HQL</span></strong><strong><span>（</span></strong><strong><span>Hibernate Query Language</span></strong><strong><span>）</span></strong><strong></strong></p>
<p><span>&nbsp;<strong><span>PS:</span></strong></span></p>
<p><span>&nbsp;1:HOL</span><span>是不区分大小写的</span><span>,</span><span>但名称是区分大小写的</span><span>.</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp; </span>2:</span><span>如果</span><span>User</span><span>類別提供有適當的建構方法，則可以在使用</span><span>HQL</span><span>時直接指定新建一個物件傳回</span></p>
<p><span>Query query = session.createQuery("select new User(user.name, user.age) from User as user");</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>3.</span><span> </span><span>如果試圖使用</span><span>Session</span><span>的</span><span>saveOrupdate()</span><span>方法，則會新增一筆資料而不是更新原有的資料。</span></p>
<p><span><span>&nbsp;&nbsp; </span>&nbsp;4. </span><span>還可以結合</span><span>having</span><span>子句，例如只將平均大於</span><span>20</span><span>的資料分組顯示出來：</span></p>
<p align=left><span>Query query = session.createQuery("select user.sex, avg(user.age) from User user group by user.sex having avg(user.age) &gt; 20");</span></p>
<p><span><span>&nbsp;&nbsp; </span>5. </span><span>更新与删除的时候</span><span> </span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span>Session session = sessionFactory.openSession();</span></p>
<p><span>Transaction tx= session.beginTransaction();</span></p>
<p><span>Query query = session.createQuery("update User set name='momor' where name='bbb'");</span></p>
<p><span>query.executeUpdate();</span></p>
<p><span>tx.commit();</span></p>
<p><span>session.close();</span></p>
<p>&nbsp;</p>
<p><strong><span>Hibernate:HQL/QBC</span></strong><strong><span>查询语</span></strong><strong><span>言比</span></strong><strong><span>较</span></strong><strong><span>的用法</span></strong><strong></strong></p>
<p align=left><strong><span>Hib</span></strong><strong><span>的</span></strong><strong><span>检</span></strong><strong><span>索方式</span></strong><span><br>1'</span><span>导</span><span>航</span><span>对</span><span>象</span><span>图检</span><span>索方式。通</span><span>过</span><span>已</span><span>经</span><span>加</span><span>载</span><span>的</span><span>对</span><span>象，</span><span>调</span><span>用</span><span>.iterator()</span><span>方法可以得到</span><span>order</span><span>对</span><span>象</span><span><br></span><span>如果是首次</span><span>执</span><span>行此方法，</span><span>Hib</span><span>会从数据</span><span>库</span><span>加</span><span>载关联</span><span>的</span><span>order</span><span>对</span><span>象，否</span><span>则</span><span>就从</span><span>缓</span><span>存中得到。</span><span><br></span><span>2'OID</span><span>检</span><span>索方式。通</span><span>过</span><span>session</span><span>的</span><span>get</span><span>，</span><span>load</span><span>方法知道了</span><span>OID</span><span>的情况下可以使用</span><span><br>3'HQL</span><span>检</span><span>索方式。使用面向</span><span>对</span><span>象的</span><span>HQL</span><span>查询语</span><span>句</span><span>session</span><span>的</span><span>find</span><span>方法利用</span><span>HQL</span><span>来</span><span>查询</span><span><br>4'QBC</span><span>检</span><span>索方式。</span><span>利用</span><span>QBCAPI</span><span>来</span><span>检</span><span>索它是封装了基于字符串的</span><span>查询语</span><span>句</span><span><br>5'</span><span>本地的</span><span>SQL</span><span>检</span><span>索方式。使用本地数据</span><span>库</span><span>的</span><span>SQL</span><span>查询语</span><span>句</span><span>Hib</span><span>会</span><span>负责</span><span>把</span><span>检</span><span>索到的</span><span>JDBC</span><span>结</span><span>果集映射</span><span>为</span><span>持久化</span><span>对</span><span>象</span><span>图</span><span>。</span><span><br><br></span><span>五</span><span>种检</span><span>索方式的使用</span><span>场</span><span>合和特点：</span><span><br><br>HQL&nbsp;</span><span>：</span>&nbsp;<span>是面向</span><span>对</span><span>象的</span><span>查询语</span><span>言，同</span><span>SQL</span><span>有些相似是</span><span>Hib</span><span>中最常用的方式。</span><span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>查询设</span><span>定各</span><span>种查询</span><span>条件。</span><span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>支持投影</span><span>查询</span><span>，</span><span>检</span><span>索出</span><span>对</span><span>象的部分属性。</span><span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>支持分</span><span>页查询</span><span>，允</span><span>许</span><span>使用</span><span>having</span><span>和</span><span>group&nbsp;by<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>提供内制的聚集函数，</span><span>sum()</span><span>，</span><span>min()</span><span>，</span><span>max()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>能</span><span>调</span><span>用用</span><span>户</span><span>的自定</span><span>义</span><span>SQL<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>支持子</span><span>查询</span><span>，嵌入式</span><span>查询</span><span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span>支持</span><span>动态绑</span><span>定参数</span><span><br></span><span>建</span><span>议</span><span>使用</span><span>Query</span><span>接口替</span><span>换</span><span>session</span><span>的</span><span>find</span><span>方法。</span><span><br>&nbsp;&nbsp;&nbsp;Query&nbsp;Q&nbsp;=&nbsp;session.createQuery("from&nbsp;customer&nbsp;as&nbsp;c&nbsp;where&nbsp;c.name&nbsp;=&nbsp;:customerName"&nbsp;+&nbsp;"and&nbsp;c.age&nbsp;=&nbsp;:customerAge");<br>&nbsp;&nbsp;&nbsp;query.setString&nbsp;("customerName"&nbsp;,&nbsp;"tom");<br>&nbsp;&nbsp;&nbsp;query.setInteger("customerAge"&nbsp;,&nbsp;"21");<br>&nbsp;&nbsp;&nbsp;list&nbsp;result&nbsp;=&nbsp;query.list();<br>QBC&nbsp;:&nbsp;&nbsp;QBCAPI</span><span>提供了另一</span><span>种</span><span>方式，主要是</span><span>Criteria</span><span>接口、</span><span>Criterion</span><span>接口和</span><span>Expression</span><span>类</span><span><br>&nbsp;&nbsp;&nbsp;Criteria&nbsp;criteria&nbsp;=&nbsp;session.createCriteria(customer.class);<br>&nbsp;&nbsp;&nbsp;Criterion&nbsp;criterion1&nbsp;=&nbsp;Expression.like("name","t%");<br>&nbsp;&nbsp;&nbsp;Criterion&nbsp;criterion2&nbsp;=&nbsp;Expression.eq("age",new&nbsp;Integer(21));<br>&nbsp;&nbsp;&nbsp;Critera&nbsp;=&nbsp;criteria.add(criterion1)&nbsp;;<br>&nbsp;&nbsp;&nbsp;Critera&nbsp;=&nbsp;criteria.add(criterion2)&nbsp;;<br>&nbsp;&nbsp;&nbsp;list&nbsp;result&nbsp;=&nbsp;criteria.list();&nbsp;<br>&nbsp;&nbsp;&nbsp;</span><span>或是：</span><span>&nbsp;list&nbsp;result&nbsp;=&nbsp;session.createCriteria(Customer.class).add(Expression.eq("this.name","tom")).list();&nbsp;<br>SQL&nbsp;:&nbsp;&nbsp;</span><span>采用</span><span>HQL</span><span>和</span><span>QBC</span><span>检</span><span>索</span><span>时</span><span>，</span><span>Hib</span><span>生成</span><span>SQL</span><span>语</span><span>句适用所有数据</span><span>库</span><span>。</span><span><br>&nbsp;&nbsp;&nbsp;Query&nbsp;query&nbsp;&nbsp;=&nbsp;session.createSQLQuery("select&nbsp;{c.*}&nbsp;from&nbsp;customers&nbsp;c&nbsp;where&nbsp;c.name&nbsp;like&nbsp;:&nbsp;customername&nbsp;"&nbsp;+&nbsp;"and&nbsp;c.age&nbsp;=&nbsp;:customerage","c",customer.calss);<br>&nbsp;&nbsp;&nbsp;query.setString("customername","tom");<br>&nbsp;&nbsp;&nbsp;query.setInteger("customerage","21");<br>&nbsp;&nbsp;&nbsp;list&nbsp;result&nbsp;=&nbsp;query.list();<br>/////////////</span><span>多</span><span>态查询</span><span><br>&nbsp;&nbsp;&nbsp;HQL&nbsp;</span><span>：</span><span>session.createQuery("from&nbsp;employee");<br>&nbsp;&nbsp;&nbsp;QBC&nbsp;</span><span>：</span><span>session.createCriteria(employee.class);<br>&nbsp;&nbsp;&nbsp;HQL&nbsp;:&nbsp;session.createQuery("from&nbsp;hourlyEmployee");<br>&nbsp;&nbsp;&nbsp;QBC&nbsp;:&nbsp;session.createCriteria(hourlyEmployee.class);<br>&nbsp;&nbsp;&nbsp;</span><span>下面的</span><span>HQL</span><span>查询语</span><span>句将</span><span>检</span><span>索出所有的持久化</span><span>对</span><span>象：</span><span><br>&nbsp;&nbsp;&nbsp;from&nbsp;java.lang.Object&nbsp;;<br>&nbsp;&nbsp;&nbsp;from&nbsp;java.io.serializable&nbsp;;<br>////////////</span><span>查询</span><span>的排序</span><span><br>&nbsp;&nbsp;&nbsp;1'</span><span>查询结</span><span>果按照客</span><span>户</span><span>姓名升序排列：</span><span><br>&nbsp;&nbsp;&nbsp;HQL&nbsp;</span><span>：</span><span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Query&nbsp;query&nbsp;=&nbsp;session.createQuery&nbsp;("from&nbsp;customer&nbsp;c&nbsp;order&nbsp;by&nbsp;c.name");<br>&nbsp;&nbsp;&nbsp;QBC&nbsp;</span><span>：</span><span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Criteria&nbsp;criteria&nbsp;=&nbsp;session.createCriteria(customer.class);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;criteria.addOrder(order.asc("name"));<br>&nbsp;&nbsp;&nbsp;HQL&nbsp;:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Query&nbsp;query&nbsp;=&nbsp;session.createQuery&nbsp;("from&nbsp;customer&nbsp;c&nbsp;order&nbsp;by&nbsp;c.name&nbsp;asc&nbsp;,&nbsp;c.age&nbsp;desc");<br>&nbsp;&nbsp;&nbsp;QBC&nbsp;:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Criteria&nbsp;criteria&nbsp;=&nbsp;session.createCriteria(customer.class);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;criteria.addOrder(order.asc&nbsp;("name"));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;criteria.addOrder(order.desc("age"));&nbsp;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;import&nbsp;net.sf.hibernate.pression.Order<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;import&nbsp;mypack.Order<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;...........<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Criteria&nbsp;criteria&nbsp;=&nbsp;session.createCritria&nbsp;(mypack.Order.class);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;criteria.addOrder(net.sf.hibernate.Order.asc("name"));<br>///////////HQL</span><span>语</span><span>句的参数</span><span>绑</span><span>定</span><span>Query</span><span>接口提供了</span><span>绑</span><span>定各</span><span>种</span><span>Hib</span><span>映射</span><span>类</span><span>型的方法。</span><span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setBinary()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setString()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setBoolean()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setByte()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setCalendar()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setCharacter()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setDate()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setDouble()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setText()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setTime()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setTimestamp()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setEntity()//</span><span>把参数与一个持久化</span><span>类</span><span>的事例</span><span>绑</span><span>定</span><span>lsit&nbsp;result&nbsp;=&nbsp;session.createQuery("from&nbsp;order&nbsp;o&nbsp;where&nbsp;o.customer&nbsp;=&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:customer").setEntity("customer"&nbsp;,&nbsp;customer).list&nbsp;;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setParameter()//</span><span>绑</span><span>定任意</span><span>类</span><span>型的参数</span><span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setProperties()//</span><span>把命名参数与一个</span><span>对</span><span>象的属性</span><span>值绑</span><span>定</span><span>&nbsp;Query&nbsp;query&nbsp;=&nbsp;session.createQuery("from&nbsp;customer&nbsp;c&nbsp;where&nbsp;c.name&nbsp;=:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name&nbsp;"&nbsp;+&nbsp;"and&nbsp;c.age&nbsp;=:age"&nbsp;);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Query.setProperties(customer);&nbsp;</span></p>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/19851985lili/aggbug/117584.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-05-15 14:05 <a href="http://www.blogjava.net/19851985lili/articles/117584.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HibenateMinute(一)</title><link>http://www.blogjava.net/19851985lili/articles/117581.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 15 May 2007 06:02:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/117581.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/117581.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/117581.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/117581.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/117581.html</trackback:ping><description><![CDATA[&nbsp;
<p><span>@ </span><span>Hibernate3.0 </span><span><span>&#224;</span></span><span>JBOSS</span></p>
<p><span>@ </span><span>ORM</span><span> </span><span><span>&#224;</span></span><span>「</span><span>对象</span><span>/</span><span>对应关系</span><span>」（</span><span>Object/Relational Mapping</span><span>）</span></p>
<p><span>@ </span><span>Hibernate3.0</span><span> </span><span>依赖底层的</span><span>JDBC2.0</span></p>
<p><strong>&nbsp;</strong></p>
<p><strong><span><a href="http://www.blogjava.net/19851985lili/articles/97628.html"><span>Hibernate</span><span><span>入</span></span><span><span>门</span></span><span> - </span><span><span>包作用</span></span><span><span>详</span></span><span><span>解</span></span><span><span> </span></span></a></span></strong><strong><span>(</span></strong><span>2</span><span>5</span><span>个</span><span>jar</span><strong><span>)</span></strong></p>
<p><span>@</span><span>必</span><span>须</span><span>的</span><span>jar</span></p>
<p><strong><span>hibernate</span></strong><strong><span>3.0</span></strong><strong><span>.jar:</span></strong><span> </span><span>必</span><span>须</span><span>使用的</span><span>jar</span><span>包</span><span> </span></p>
<p><strong><span>antlr.jar:</span></strong><span> Hibernate</span><span>使用</span><span>ANTLR</span><span>来</span><span>产</span><span>生</span><span>查询</span><span>分析</span><span>器</span></p>
<p><strong><span>EHCache</span></strong><strong><span>.</span></strong><strong><span>jar</span></strong><strong><span>:</span></strong><span> </span><span>Hibernate</span><span>可以使用不同</span><span>cache</span><span>缓</span><span>存工具作</span><span>为</span><span>二</span><span>级缓</span><span>存。</span><span>缺省的</span><span>cache</span><span>缓</span><span>存</span></p>
<p><strong><span>cglib-asm.jar:</span></strong><span> Hibernate</span><span>用它来</span><span>实现</span><span>PO</span><span>字</span><span>节码</span><span>的</span><span>动态</span><span>生成，非常核心的</span><span>库</span><span>，</span></p>
<p><span>　　</span><strong><span>dom4j.jar:</span></strong><span> </span><span>是一个</span><span>Java</span><span>的</span><span>XML API</span><span>，</span><span> Hibernate</span><span>用它来</span><span>读</span><span>写配置文件。</span><span> </span></p>
<p><span>　　</span><strong><span>odmg.jar:</span></strong><span>是一个</span><span>ORM</span><span>的</span><span>规</span><span>范，</span><span>Hibernate</span><span>实现</span><span>了</span><span>ODMG</span><span>规</span><span>范，</span><span>这</span><span>是一个核心的</span><span>库</span><span>，</span><span>　　</span><strong><span>commons-collections.jar</span></strong><strong><span>：</span></strong><span>包含了一些</span><span>Apache</span><span>开发</span><span>的集合</span><span>类</span></p>
<p><strong><span>　　</span></strong><strong><span>commons-beanutils.jar</span></strong><strong><span>：</span></strong><span>，包含了一些</span><span>Bean</span><span>工具</span><span>类类</span><span>。必</span><span>须</span><span>使用的</span><span>jar</span><span>包。</span><span> </span></p>
<p><span>　<strong>　</strong></span><strong><span>commons-lang.jar:</span></strong><span>些数据</span><span>类</span><span>型工具</span><span>类</span><span>，是</span><span>java.lang.*</span><span>的</span><span>扩</span><span>展。必</span><span>须</span><span>使用的</span><span>jar</span><span>包</span></p>
<p><strong><span>commons-logging.jar:</span></strong><span>包含了日志功能</span><span>。</span></p>
<p><span>@</span><span>可</span><span>选</span><span>的</span><span>:</span><span> </span></p>
<p><span>　　</span><strong><span>ant.jar:</span></strong><span> Ant</span><span>编译</span><span>工具的</span><span>jar</span><span>包，用来</span><span>编译</span><span>Hibernate</span><span>源代</span><span>码</span><span>的。</span></p>
<p><span>　　</span><strong><span>optional.jar</span></strong><strong><span>：</span></strong><span> </span><span>Ant</span><span>的一个</span><span>辅</span><span>助包。</span><span> </span></p>
<p><span>　　</span><strong><span>c3p0.jar</span></strong><strong><span>：</span></strong><strong><span> </span></strong><span>C3PO</span><span>是一个数据</span><span>库连</span><span>接池，</span><span>Hibernate</span><span>可以配置</span><span>为</span><span>使用</span><span>C3PO</span><span>连</span><span>接池。</span></p>
<p><span>　　</span><strong><span>proxool.jar</span></strong><strong><span>：</span></strong><span> </span><span>也是一个</span><span>连</span><span>接池，同上。</span><span> </span></p>
<p><span>　<strong>　</strong></span><strong><span>commons-pool.jar</span></strong><strong><span>:</span></strong><strong><span>commons-dbcp.jar: </span></strong><span>&nbsp;Tomcat4</span><span>的</span><span>连</span><span>接池也是</span><span>DBCP</span><span>。</span></p>
<p><span>在</span><span>EJB</span><span>中使用</span><span>Hibernate</span><span>，一定要用</span><span>App Server</span><span>的</span><span>连</span><span>接池，否</span><span>则</span><span>容器管理事</span><span>务</span><span>不起作用</span><span>.</span></p>
<p><span>　<strong>　</strong></span><strong><span>connector.jar:</span></strong><strong><span>　</span></strong><span>JCA </span><span>规</span><span>范，</span><span> </span><span>App Server</span><span>上把</span><span>Hibernate</span><span>配置</span><span>为</span><span>Connector</span><span>的</span><span>话</span><span>用</span><span>。</span></p>
<p><strong><span>J</span></strong><strong><span>aas.jar:</span></strong><span> </span><span>JAAS</span><span>是用来</span><span>进</span><span>行</span><span>权</span><span>限</span><span>验证</span><span>的，已</span><span>经</span><span>包含在</span><span>JDK1.4</span><span>里面了。</span></p>
<p><strong><span>jcs.jar</span></strong><strong><span>：</span></strong><span>　如果你准</span><span>备</span><span>在</span><span>Hibernate</span><span>中使用</span><span>JCS</span><span>的</span><span>话</span><span>，那</span><span>么</span><span>必</span><span>须</span><span>包括它，否</span><span>则</span><span>就不用。</span><span> </span></p>
<p><strong><span>jdbc2_0-stdext.jar:</span></strong><span>　</span><span>JDBC2.0</span><span>的</span><span>扩</span><span>展包，一般来</span><span>说</span><span>数据</span><span>库连</span><span>接池会用上它。</span></p>
<p><strong><span>jta.jar</span></strong><strong><span>：</span></strong><strong><span> </span></strong><span>JTA</span><span>规</span><span>范，当</span><span>Hibernate</span><span>使用</span><span>JTA</span><span>的</span><span>时</span><span>候需要，</span></p>
<p><span>j<strong>unit.jar:</strong></span><span>　</span><span>Junit</span><span>包，当你运行</span><span>Hibernate</span><span>自</span><span>带</span><span>的</span><span>测试</span><span>代</span><span>码</span><span>的</span><span>时</span><span>候需要，否</span><span>则</span><span>就不用。</span></p>
<p><strong><span>xalan.jar</span></strong><strong><span>:</span></strong><strong><span>xerces.jar</span></strong><strong><span>:</span></strong><strong><span>xml-apis.jar: </span></strong><strong></strong></p>
<p><span>Xerces</span><span>是</span><span>XML</span><span>解析器，</span><span>Xalan</span><span>是格式化器，</span><span>xml-apis</span><span>实际</span><span>上是</span><span>JAXP</span><span>。一般</span><span>App Server</span><span>都会</span><span>带</span><span>上，</span><span> </span><span>Hibernate</span><span>用</span><span>XML</span><span>只不</span><span>过</span><span>是</span><span>读</span><span>取配置文件</span><span>。</span><span>&nbsp;&nbsp;</span></p>
<p>&nbsp;</p>
<p><span>@<strong> </strong></span><strong><span>log4j.properties</span></strong></p>
<p><span><span>Hibernate</span></span><span>包的</span><span>etc</span><span>目录下的</span><span>log4j.properties</span><span>复制到</span><span>Hibernate</span><span>项目的</span><span>Classpath</span><span>下</span><span>,</span></p>
<p><span>修改</span><span>log4j.logger.org.hibernate</span><span> =</span><span> error</span><span>!</span></p>
<p><span>@ </span><strong><span>实体对象的加载</span></strong><span>!</span></p>
<p><span>&nbsp;</span><span>&lt;hibernate-configuration&gt; </span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>&lt;session-factory&gt;&nbsp;</span></p>
<p><span>&nbsp;</span><span>&lt;!-- </span><span>对象与数据库表的映射文件</span><span> </span><span>--&gt; </span></p>
<p><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><strong><em><span>&lt;mapping resource="onlyfun/caterpillar/User.hbm.xml"/&gt; </span></em></strong><strong><em></em></strong></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span>&lt;/session-factory&gt; </span></p>
<p><span>&lt;/hibernate-configuration&gt;</span></p>
<p><span>@ </span><strong><span>获得</span></strong><strong><span>负责管理</span></strong><strong><span>Hibernate</span></strong><strong><span>的配置信息的</span></strong><strong><span>Configuration</span></strong><strong><span>用</span></strong><strong><span>session</span></strong><strong><span>的</span></strong><strong><span>操作</span></strong></p>
<p><span>Configuration config = new Configuration().configure();</span></p>
<p><strong><span>//</span></strong><span>configure()</span><strong><span>默认</span></strong><strong><span>./</span></strong><strong><span>Hibernate</span></strong><strong><span>.</span></strong><strong><span>cfg.xml; </span></strong><strong><span>当然也可以指定</span></strong><strong><span>URL</span></strong></p>
<p><span>SessionFactory sessionFactory = config.buildSessionFactory();</span></p>
<p><span>Session session = sessionFactory.openSession();</span></p>
<p><span>Transaction tx= session.beginTransaction();</span></p>
<p><span>session.save(user);</span><strong><span>//</span></strong><strong><span> user</span></strong><strong><span>实体</span></strong></p>
<p><span>tx.commit();</span></p>
<p><span>session.close();</span></p>
<p><span>sessionFactory.close();</span></p>
<p><span>@ </span><strong><span>Criteria</span></strong><strong><span>的</span></strong><strong><span>API</span></strong><strong><span>不完善</span></strong><span>.</span></p>
<p><span>Session</span><span>中的</span><strong><span>find()</span></strong><strong><span>方法被取消了</span></strong><span>，必須使用</span><span>Session</span><span>的</span><span>createQuery()</span><span>建立</span><span>Query</span><span>實例，並使用</span><span>list()</span><span>方法來取代。</span><span>Session</span><span>的</span><strong><span>iterate()</span></strong><strong><span>被取消了</span></strong><span>，由</span><span>Query</span><span>介面上的</span><span>iterator()</span><span>來取代，詳請看</span><span> <span><a href="file:///E:/_DataBank/hibenate/HibernateGossip/HibernateGossip/HibernateGossip/QueryListIterator.html"><strong>Query.list()</strong><strong><span><span>、</span></span>iterator()</strong></a></span></span><span>。</span></p>
<p align=left><span>新增</span><span> update </span><span>語句</span></p>
<p align=left><strong><span>Query query = session.createQuery("update User set age=30 where id=1");</span></strong><strong></strong></p>
<p align=left><strong><span>query.executeUpdate();</span></strong></p>
<p align=left><span>新增</span><span> delete </span><span>語句</span></p>
<p align=left><strong><span>Query query = session.createQuery("delete User where age&lt;20");</span></strong><strong></strong></p>
<p align=left><strong><span>query.executeUpdate();</span></strong></p>
<p><span>&nbsp;&nbsp;</span><span><span>Query</span></span><span><span>:</span></span></p>
<p><span>&nbsp;&nbsp;</span><span>1:</span><span>query</span><span> </span><span>= </span><span>session.createQuery("from User user where user.name like ?");</span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>query.setParameter(0, "caterpillar");</span></p>
<p><span><span>&nbsp;&nbsp; </span>2 :</span><span>Query query = session.createQuery("select user.name from User as user where user.age &gt; </span><span>:minAge</span><span>"); </span><span><br><span>query.setInteger("</span></span><span>minAge</span><span>", 25)<strong>;</strong></span><strong></strong></p>
<p><strong><span>4.</span></strong><span> </span><strong><span>悲觀鎖定（</span></strong><strong><span>Pessimistic Locking</span></strong><strong><span>）</span></strong><strong></strong></p>
<p><strong><span><span>&nbsp;&nbsp; </span></span></strong><span>悲觀鎖定通常透過系統或資料庫本身的功能來實現，依賴系統或資料庫本身提供的鎖定機制，</span><span>Hibernate</span><span>即是如此，可以利用</span><span>Query</span><span>或</span><span>Criteria</span><span>的</span><span>setLockMode()</span><span>方法來設定要鎖定的表或列（</span><span>Row</span><span>）及其鎖定模式，可設定的鎖定模式有以下的幾個：</span><span> </span></p>
<ul type=disc>
    <li><span>LockMode.UPGRADE</span><span>：利用資料庫的</span><span>for update</span><span>子句進行鎖定。</span><span> </span></li>
    <li><span>LockMode.UPGRADE_NOWAIT</span><span>：使用</span><span>for update nowait</span><span>子句進行鎖定，在</span><span>Oracle</span><span>資料庫中使用</span></li>
</ul>
<p><span>Query query = session.createQuery("from User user");</span></p>
<p><span>query.setLockMode("user", LockMode.UPGRADE);</span></p>
<p align=left><span>也可以在使用</span><span>Session</span><span>的</span><span>load()</span><span>或是</span><span>lock()</span><span>時指定鎖定模式以進行鎖定。</span><span> </span></p>
<p align=left><span>另外還有三種加鎖模式</span><span>Hibernate</span><span>內</span><span>部自動對資料進行鎖定，與資料庫無關：</span></p>
<ul type=disc>
    <li><span>LockMode.WRITE</span><span>：在</span><span>insert</span><span>或</span><span>update</span><span>時進行鎖定，</span><span>Hibernate</span><span>會在</span><span>save()</span><span>方法時自動獲得鎖定。</span><span> </span></li>
    <li><span>LockMode.READ</span><span>：在讀取記</span><span>錄</span><span>時</span><span>Hibernate</span><span>會自動獲得鎖定。</span>&nbsp;</li>
    <li><span>LockMode.NONE</span><span>：沒有鎖定。</span><span> </span></li>
</ul>
<p><span>如果資料庫不支援所指定的鎖定模式，</span><span>Hibernate</span><span>會選擇一個合適的鎖定替換，而不是丟出一個例外</span></p>
<p><span>5: </span><span><a href="file:///E:/_DataBank/hibenate/HibernateGossip/HibernateGossip/HibernateGossip/LifecycleValidatable.html"><strong>Lifecycle </strong><strong><span><span>介面、</span></span>Validatable </strong><strong><span><span>介面</span></span></strong></a></span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>可以在實體物件定義時實作</span><span>Lifecycle</span><span>介面，這個介面定義如下：</span></p>
<p align=left><strong><span>package org.hibernate.classic;</span></strong><strong></strong></p>
<p align=left><strong><span>import java.io.Serializable;</span></strong><strong></strong></p>
<p align=left><strong><span>import org.hibernate.CallbackException;</span></strong><strong></strong></p>
<p align=left><strong><span>import org.hibernate.Session;</span></strong><strong></strong></p>
<p align=left><strong><span>public interface Lifecycle {</span></strong><strong></strong></p>
<p align=left><strong><span>&nbsp;&nbsp;&nbsp; public static final boolean VETO = true;</span></strong><strong></strong></p>
<p align=left><strong><span>&nbsp;&nbsp;&nbsp; public static final boolean NO_VETO = false;</span></strong><strong></strong></p>
<p align=left><strong><span>&nbsp;&nbsp;&nbsp; public boolean onSave(Session s) throws CallbackException;</span></strong><strong></strong></p>
<p align=left><strong><span>&nbsp;&nbsp;&nbsp; public boolean onUpdate(Session s) throws CallbackException;</span></strong><strong></strong></p>
<p align=left><strong><span>&nbsp;&nbsp;&nbsp; public boolean onDelete(Session s) throws CallbackException;</span></strong><strong></strong></p>
<p align=left><strong><span>&nbsp;&nbsp;&nbsp; public void onLoad(Session s, Serializable id);</span></strong><strong></strong></p>
<p align=left><strong><span>}</span></strong></p>
<p align=left><span>當物件實作</span><span>Lifecycle</span><span>介面時，會在</span><span>save()</span><span>、</span><span>update()</span><span>、</span><span>delete()</span><span>、</span><span>load()</span><span>等方法執行之前呼叫對應的</span><span>onSave()</span><span>、</span><span> onUpdate()</span><span>、</span><span>onDelete()</span><span>與</span><span>onLoad()</span><span>，其中</span><span>onSave()</span><span>、</span><span>onUpdate()</span><span>、</span><span>onDelete()</span><span>與</span><span>onLoad() </span><span>若傳回</span><span>true</span><span>或丟出</span><span>CallbackException</span><span>，則對應的操作中止。</span></p>
<p align=left><span>可以在實體物件定義時實作</span><span>Validatable</span><span>介面，其定義如下：</span></p>
<p align=left><strong><span>package org.hibernate.classic;</span></strong><strong></strong></p>
<p align=left><strong><span>public interface Validatable {</span></strong><strong></strong></p>
<p align=left><strong><span>&nbsp;&nbsp;&nbsp; public void validate() throws ValidationFailure;</span></strong><strong></strong></p>
<p align=left><strong><span>}</span></strong></p>
<p><span>如果定義時實作了</span><span>Validatable</span><span>介面，當物件被持久化之前會呼叫</span><span>validate()</span><span>方法，如果丟出</span><span>ValidationFailure</span><span>，則驗證失敗，物件的資料不會儲存至資料庫中</span></p>
<p><span><a href="file:///E:/_DataBank/hibenate/HibernateGossip/HibernateGossip/HibernateGossip/Interceptor.html"><strong>Interceptor </strong><strong><span><span>介面</span></span></strong></a></span></p>
<p><span><span>&nbsp;&nbsp;&nbsp; </span></span><span>您可以在開</span><span>啟</span><span>Session</span><span>時載入一個自訂</span><span>Interceptor</span><span>，這個</span><span>Interceptor</span><span>會在對應的動作發生之前呼叫對應的方法，方法是讓您定義的</span><span>Interceptor</span><span>實作</span><span>Interceptor</span><span>介面，介面的定義如下：</span></p>
<p align=left><span>package org.hibernate;</span></p>
<p align=left><span>import java.io.Serializable;</span></p>
<p align=left><span>import java.util.Iterator;</span></p>
<p align=left><span>import org.hibernate.type.Type;</span></p>
<p align=left><span>public interface Interceptor {</span></p>
<p align=left><span>&nbsp; &nbsp; // </span><span>載入物件之前執行</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException;</span></p>
<p align=left><span>&nbsp; &nbsp; // flush </span><span>時，如果發現有</span><span>Dirty data</span><span>，則執行此方法</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types) throws CallbackException;</span></p>
<p align=left><span>&nbsp; &nbsp; // </span><span>儲存物件前執行</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException;</span></p>
<p align=left><span>&nbsp; &nbsp; // </span><span>刪除物件前執行</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException;</span></p>
<p align=left><span>&nbsp; &nbsp; // </span><span>在</span><span> flush </span><span>前執行</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; public void preFlush(Iterator entities) throws CallbackException;</span></p>
<p align=left><span>&nbsp; &nbsp; // </span><span>在</span><span> flush </span><span>後執行</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; public void postFlush(Iterator entities) throws CallbackException;</span></p>
<p align=left><span>&nbsp; &nbsp; // </span><span>判斷傳入的物件是否為</span><span> transient </span><span>狀</span><span>態</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; public Boolean isTransient(Object entity);</span></p>
<p align=left><span>&nbsp; &nbsp; // flush </span><span>前呼叫這個方法判斷</span><span> Dirty data</span></p>
<p align=left><span>&nbsp; &nbsp; // </span><span>傳回</span><span>Dirty data</span><span>屬性索引或</span><span>null</span><span>採預設行為</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; public int[] findDirty(Object entity, Serializable id, Object[] currentState, Object[] previousState, String[] propertyNames, Type[] types);</span></p>
<p align=left><span>&nbsp; &nbsp; // </span><span>手動建立實體物件，如果傳回</span><span> null</span><span>，則使用預設的建構方法建立實例</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; </span><span>public Object instantiate(String entityName, EntityMode entityMode, Serializable id) throws CallbackException;</span></p>
<p align=left><span>&nbsp; &nbsp; // </span><span>傳回實體名稱</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; public String getEntityName(Object object) throws CallbackException;</span></p>
<p align=left><span>&nbsp; &nbsp; // </span><span>取得實體物件</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; public Object getEntity(String entityName, Serializable id) throws CallbackException;</span></p>
<p align=left><span>&nbsp; &nbsp; //&nbsp;beginTransaction() </span><span>之後執行</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; public void afterTransactionBegin(Transaction tx);</span></p>
<p align=left><span>&nbsp; &nbsp; // </span><span>在事務完成前執行</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; public void beforeTransactionCompletion(Transaction tx);</span></p>
<p align=left><span>&nbsp; &nbsp; // </span><span>在事務完成後執行</span></p>
<p align=left><span>&nbsp;&nbsp;&nbsp; public void afterTransactionCompletion(Transaction tx);}</span></p>
<p align=left><span>假設您實作了</span><span>SomeInterceptor</span><span>類別：</span></p>
<p align=left><span>package onlyfun.caterpillar;</span></p>
<p align=left><span>....</span></p>
<p align=left><span>public class SomeInterceptor implements Interceptor {</span></p>
<p align=left><span>&nbsp; &nbsp; ....</span></p>
<p align=left><span>}</span></p>
<p align=left><span><br></span><span>在開</span><span>啟</span><span>Session</span><span>時，可以如下載入自訂的</span><span>Interceptor</span><span>：</span></p>
<p align=left><span>SomeInterceptor someInterceptor = new SomeInterceptor();</span></p>
<p align=left><span>Session session = sessionFactory.openSession(someInterceptor);</span></p>
<img src ="http://www.blogjava.net/19851985lili/aggbug/117581.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-05-15 14:02 <a href="http://www.blogjava.net/19851985lili/articles/117581.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> 集合类(Collections)映射</title><link>http://www.blogjava.net/19851985lili/articles/108139.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 03 Apr 2007 02:32:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/108139.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/108139.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/108139.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/108139.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/108139.html</trackback:ping><description><![CDATA[<h2 class=title>&nbsp;</h2>
<div class=sect1 lang=zh-cn>
<h2 class=title style="CLEAR: both">&nbsp;</h2>
<p><a name=collections-persistent-translate-comment></a>(译者注：在阅读本章的时候，以后整个手册的阅读过程中，我们都会面临一个名词方面的问题，那就是&#8220;集合&#8221;。"Collections"和"Set"在中文里对应都被翻译为&#8220;集合&#8221;，但是他们的含义很不一样。Collections是一个超集，Set是其中的一种。大部分情况下，本译稿中泛指的未加英文注明的&#8220;集合&#8221;，都应当理解为&#8220;Collections&#8221;。在有些二者同时出现，可能造成混淆的地方，我们用&#8220;集合类&#8221;来特指&#8220;Collecions&#8221;,&#8220;集合(Set)&#8221;来指"Set"，一般都会在后面的括号中给出英文。希望大家在阅读时联系上下文理解，不要造成误解。 与此同时，&#8220;元素&#8221;一词对应的英文&#8220;element&#8221;，也有两个不同的含义。其一为集合的元素，是内存中的一个变量；另一含义则是XML文档中的一个标签所代表的元素。也请注意区别。 本章中,特别是后半部分是需要反复阅读才能理解清楚的。如果遇到任何疑问,请记住,英文版本的reference是惟一标准的参考资料。) </p>
<p>Hibernate要求持久化集合值字段必须声明为接口，比如： </p>
<pre class=programlisting>public class Product {
private String serialNumber;
private Set parts = new HashSet();
public Set getParts() { return parts; }
void setParts(Set parts) { this.parts = parts; }
public String getSerialNumber() { return serialNumber; }
void setSerialNumber(String sn) { serialNumber = sn; }
}</pre>
<p>实际的接口可能是<tt class=literal>java.util.Set</tt>, <tt class=literal>java.util.Collection</tt>, <tt class=literal>java.util.List</tt>, <tt class=literal>java.util.Map</tt>, <tt class=literal>java.util.SortedSet</tt>, <tt class=literal>java.util.SortedMap</tt> 或者...任何你喜欢的类型！("任何你喜欢的类型" 代表你需要编写 <tt class=literal>org.hibernate.usertype.UserCollectionType</tt>的实现.) </p>
<p>注意我们是如何用一个<tt class=literal>HashSet</tt>实例来初始化实例变量的.这是用于初始化新创建(尚未持久化)的类实例中集合值属性的最佳方法。当你持久化这个实例时——比如通过调用<tt class=literal>persist()</tt>——Hibernate 会自动把<tt class=literal>HashSet</tt>替换为Hibernate自己的<tt class=literal>Set</tt>实现。观察下面的错误： </p>
<pre class=programlisting>Cat cat = new DomesticCat();
Cat kitten = new DomesticCat();
....
Set kittens = new HashSet();
kittens.add(kitten);
cat.setKittens(kittens);
session.persist(cat);
kittens = cat.getKittens(); //Okay, kittens collection is a Set
(HashSet) cat.getKittens(); //Error!</pre>
<p>根据不同的接口类型，被Hibernate注射的持久化集合类的表现类似<tt class=literal>HashMap</tt>, <tt class=literal>HashSet</tt>, <tt class=literal>TreeMap</tt>, <tt class=literal>TreeSet</tt> or <tt class=literal>ArrayList</tt>。 </p>
<p>集合类实例具有值类型的通常行为。当被持久化对象引用后，他们会自动被持久化，当不再被引用后，自动被删除。假若实例被从一个持久化对象传递到另一个，它的元素可能从一个表转移到另一个表。两个实体不能共享同一个集合类实例的引用。因为底层关系数据库模型的原因，集合值属性无法支持空值语义；Hibernate对空的集合引用和空集合不加区别。 </p>
<p>你不需要过多的为此担心。就如同你平时使用普通的Java集合类一样来使用持久化集合类。只是要确认你理解了双向关联的语义（后文讨论）。 </p>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=collections-mapping></a>7.2.&nbsp;集合映射（ Collection mappings ）</h2>
</div>
</div>
<div></div>
</div>
<p>用于映射集合类的Hibernate映射元素取决于接口的类型。比如， <tt class=literal>&lt;set&gt;</tt> 元素用来映射<tt class=literal>Set</tt>类型的属性。 </p>
<pre class=programlisting>&lt;class name="Product"&gt;
&lt;id name="serialNumber" column="productSerialNumber"/&gt;
&lt;set name="parts"&gt;
&lt;key column="productSerialNumber" not-null="true"/&gt;
&lt;one-to-many class="Part"/&gt;
&lt;/set&gt;
&lt;/class&gt;</pre>
<p>除了<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>
fetch="join|select|subselect"                               <span class=co>(10)</span>
batch-size="N"                                              <span class=co>(11)</span>
access="field|property|ClassName"                           <span class=co>(12)</span>
optimistic-lock="true|false"                                <span class=co>(13)</span>
node="element-name|."
embed-xml="true|false"
&gt;
&lt;key .... /&gt;
&lt;map-key .... /&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> (可选--默认为true) 可以用来关闭延迟加载，指定一直使用预先抓取（对数组不适用） </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>fetch</tt> (可选, 默认为<tt class=literal>select</tt>) 用于在外连接抓取、通过后续select抓取和通过后续subselect抓取之间选择。 </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>
        <tr>
            <td vAlign=top align=left width="5%">(12)</td>
            <td vAlign=top align=left>
            <p><tt class=literal>乐观锁</tt> (可选 - 默认为 <tt class=literal>true</tt>): 对集合的状态的改变会是否导致其所属的实体的版本增长。 (对一对多关联来说，关闭这个属性常常是有理的) </p>
            </td>
        </tr>
    </tbody>
</table>
</div>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=collections-foreignkeys></a>7.2.1.&nbsp;集合外键(Collection foreign keys)</h3>
</div>
</div>
<div></div>
</div>
<p>集合实例在数据库中依靠持有集合的实体的外键加以辨别。此外键作为<span class=emphasis><em>集合关键字段（collection key column）</em></span>（或多个字段）加以引用。集合关键字段通过<tt class=literal>&lt;key&gt;</tt> 元素映射。 </p>
<p>在外键字段上可能具有非空约束。对于大多数集合来说，这是隐含的。对单向一对多关联来说，外键字段默认是可以为空的，因此你可能需要指明 <tt class=literal>not-null="true"</tt>。 </p>
<pre class=programlisting>&lt;key column="productSerialNumber" not-null="true"/&gt;</pre>
<p>外键约束可以使用<tt class=literal>ON DELETE CASCADE</tt>。 </p>
<pre class=programlisting>&lt;key column="productSerialNumber" on-delete="cascade"/&gt;</pre>
<p>对<tt class=literal>&lt;key&gt;</tt> 元素的完整定义，请参阅前面的章节。 </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=collections-elements></a>7.2.2.&nbsp;集合元素（Collection elements）</h3>
</div>
</div>
<div></div>
</div>
<p>集合几乎可以包含任何其他的Hibernate类型，包括所有的基本类型、自定义类型、组件，当然还有对其他实体的引用。存在一个重要的区别：位于集合中的对象可能是根据&#8220;值&#8221;语义来操作（其声明周期完全依赖于集合持有者），或者它可能是指向另一个实体的引用，具有其自己的生命周期。在后者的情况下，被作为集合持有的状态考虑的，只有两个对象之间的&#8220;连接&#8221;。 </p>
<p>被包容的类型被称为<span class=emphasis><em>集合元素类型（collection element type）</em></span>。集合元素通过<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>映射。前两种用于使用值语义映射元素，后两种用于映射实体关联。 </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=collections-indexed></a>7.2.3.&nbsp;索引集合类(Indexed collections)</h3>
</div>
</div>
<div></div>
</div>
<p>所有的集合映射，除了set和bag语义的以外，都需要指定一个集合表的<span class=emphasis><em>索引字段(index column)</em></span>——用于对应到数组索引，或者<tt class=literal>List</tt>的索引，或者<tt class=literal>Map</tt>的关键字。通过<tt class=literal>&lt;map-key&gt;</tt>,<tt class=literal>Map</tt> 的索引可以是任何基础类型；若通过<tt class=literal>&lt;map-key-many-to-many&gt;</tt>，它也可以是一个实体引用；若通过<tt class=literal>&lt;composite-map-key&gt;</tt>，它还可以是一个组合类型。数组或列表的索引必须是<tt class=literal>integer</tt>类型，并且使用 <tt class=literal>&lt;list-index&gt;</tt>元素定义映射。被映射的字段包含有顺序排列的整数（默认从0开始）。 </p>
<div class=programlistingco>
<pre class=programlisting>&lt;map-key
column="column_name"                <span class=co>(1)</span>
formula="any SQL expression"        <span class=co>(2)</span>
type="type_name"                    <span class=co>(3)</span>
node="@attribute-name"
length="N"/&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>formula</tt> (可选): 用于计算map关键字的SQL公式 </p>
            </td>
        </tr>
        <tr>
            <td vAlign=top align=left width="5%">(3)</td>
            <td vAlign=top align=left>
            <p><tt class=literal>type</tt> (可选,默认为整型<tt class=literal>integer</tt>):集合索引的类型。 </p>
            </td>
        </tr>
    </tbody>
</table>
</div>
</div>
<div class=programlistingco>
<pre class=programlisting>&lt;map-key-many-to-many
column="column_name"                <span class=co>(1)</span>
formula="any SQL expression"        <span class=co>(2)</span><span class=co>(3)</span>
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>column</tt>(可选):集合索引值中外键字段的名称 </p>
            </td>
        </tr>
        <tr>
            <td vAlign=top align=left width="5%">(2)</td>
            <td vAlign=top align=left>
            <p><tt class=literal>formula</tt> (可选): 用于计算map关键字的外键的SQL公式 </p>
            </td>
        </tr>
        <tr>
            <td vAlign=top align=left width="5%">(3)</td>
            <td vAlign=top align=left>
            <p><tt class=literal>class</tt> (必需):集合的索引使用的实体类。 </p>
            </td>
        </tr>
    </tbody>
</table>
</div>
</div>
<p>假若你的表没有一个索引字段,当你仍然希望使用<tt class=literal>List</tt>作为属性类型,你应该把此属性映射为Hibernate <span class=emphasis><em>&lt;bag&gt;</em></span>。从数据库中获取的时候，bag不维护其顺序，但也可选择性的进行排序。 </p>
</div>
<p>从集合类可以产生很大一部分映射，覆盖了很多常见的关系模型。我们建议你试验schema生成工具，来体会一下不同的映射声明是如何被翻译为数据库表的。 </p>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=collections-ofvalues></a>7.2.4.&nbsp;值集合于多对多关联(Collections of values and many-to-many associations)</h3>
</div>
</div>
<div></div>
</div>
<p>任何值集合或者多对多关联需要专用的具有一个或多个外键字段的<span class=emphasis><em>collection table</em></span>、一个或多个<span class=emphasis><em>collection element column</em></span>，以及还可能有一个或多个索引字段。 </p>
<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>
formula="any SQL expression"             <span class=co>(2)</span>
type="typename"                          <span class=co>(3)</span>
length="N"
precision="N"
scale="N"
not-null="true|false"
unique="true|false"
node="element-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>
        <tr>
            <td vAlign=top align=left width="5%">(2)</td>
            <td vAlign=top align=left>
            <p><tt class=literal>formula</tt> (可选): 用于计算元素的SQL公式 </p>
            </td>
        </tr>
        <tr>
            <td vAlign=top align=left width="5%">(3)</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 association)</em></span> 使用 <tt class=literal>&lt;many-to-many&gt;</tt>元素定义. </p>
<div class=programlistingco>
<pre class=programlisting>&lt;many-to-many
column="column_name"                               <span class=co>(1)</span>
formula="any SQL expression"                       <span class=co>(2)</span>
class="ClassName"                                  <span class=co>(3)</span>
fetch="select|join"                                <span class=co>(4)</span>
unique="true|false"                                <span class=co>(5)</span>
not-found="ignore|exception"                       <span class=co>(6)</span>
entity-name="EntityName"                           <span class=co>(7)</span>
node="element-name"
embed-xml="true|false"
/&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>formula</tt> (可选): 用于计算元素外键值的SQL公式. </p>
            </td>
        </tr>
        <tr>
            <td vAlign=top align=left width="5%">(3)</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>
        <tr>
            <td vAlign=top align=left width="5%">(4)</td>
            <td vAlign=top align=left>
            <p>为此关联打开外连接抓取或者后续select抓取。这是特殊情况；对于一个实体及其指向其他实体的多对多关联进全预先抓取（使用一条单独的<tt class=literal>SELECT</tt>)，你不仅需要对集合自身打开<tt class=literal>join</tt>，也需要对<tt class=literal>&lt;many-to-many&gt;</tt>这个内嵌元素打开此属性。 </p>
            </td>
        </tr>
        <tr>
            <td vAlign=top align=left width="5%">(5)</td>
            <td vAlign=top align=left>
            <p>对外键字段允许DDL生成的时候生成一个惟一约束。这使关联变成了一个高效的一对多关联。（此句存疑：原文为This makes the association multiplicity effectively one to many.) </p>
            </td>
        </tr>
        <tr>
            <td vAlign=top align=left width="5%">(6)</td>
            <td vAlign=top align=left>
            <p><tt class=literal>not-found</tt> (可选 - 默认为 <tt class=literal>exception</tt>): 指明引用的外键中缺少某些行该如何处理： <tt class=literal>ignore</tt> 会把缺失的行作为一个空引用处理。 </p>
            </td>
        </tr>
        <tr>
            <td vAlign=top align=left width="5%">(7)</td>
            <td vAlign=top align=left>
            <p><tt class=literal>entity-name</tt> (可选): 被关联的类的实体名，作为<tt class=literal>class</tt>的替代。 </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="item_sizes"
order-by="size asc"&gt;
&lt;key column="item_id"/&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="addresses"
table="PersonAddress"
cascade="persist"&gt;
&lt;key column="personId"/&gt;
&lt;list-index column="sortOrder"/&gt;
&lt;many-to-many column="addressId" class="Address"/&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;map-key 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="CarComponents"&gt;
&lt;key column="carId"/&gt;
&lt;list-index column="sortOrder"/&gt;
&lt;composite-element class="CarComponent"&gt;
&lt;property name="price"/&gt;
&lt;property name="type"/&gt;
&lt;property name="serialNumber" column="serialNum"/&gt;
&lt;/composite-element&gt;
&lt;/list&gt;</pre>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=collections-onetomany></a>7.2.5.&nbsp;一对多关联（One-to-many Associations）</h3>
</div>
</div>
<div></div>
</div>
<p><span class=emphasis><em>一对多关联</em></span><span class=emphasis><em>通过外键</em></span>连接两个类对应的表,而没有中间集合表。 这个关系模型失去了一些Java集合的语义: </p>
<div class=itemizedlist>
<ul type=disc compact>
    <li>
    <p>一个被包含的实体的实例只能被包含在一个集合的实例中 </p>
    <li>
    <p>一个被包含的实体的实例只能对应于集合索引的一个值中 </p>
    </li>
</ul>
</div>
<p>一个从<tt class=literal>Product</tt>到<tt class=literal>Part</tt>的关联需要关键字字段,可能还有一个索引字段指向<tt class=literal>Part</tt>所对应的表。 <tt class=literal>&lt;one-to-many&gt;</tt>标记指明了一个一对多的关联。 </p>
<div class=programlistingco>
<pre class=programlisting>&lt;one-to-many
class="ClassName"                                  <span class=co>(1)</span>
not-found="ignore|exception"                       <span class=co>(2)</span>
entity-name="EntityName"                           <span class=co>(3)</span>
node="element-name"
embed-xml="true|false"
/&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>
        <tr>
            <td vAlign=top align=left width="5%">(2)</td>
            <td vAlign=top align=left>
            <p><tt class=literal>not-found</tt> (可选 - 默认为<tt class=literal>exception</tt>): 指明若缓存的标示值关联的行缺失,该如何处理: <tt class=literal>ignore</tt> 会把缺失的行作为一个空关联处理。 </p>
            </td>
        </tr>
        <tr>
            <td vAlign=top align=left width="5%">(3)</td>
            <td vAlign=top align=left>
            <p><tt class=literal>entity-name</tt> (可选): 被关联的类的实体名，作为<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>NOT NULL</tt>,你必须把<tt class=literal>&lt;key&gt;</tt>映射声明为<tt class=literal>not-null="true"</tt>,或者使用<span class=emphasis><em>双向关联</em></span>，并且标明<tt class=literal>inverse="true"</tt>。参阅本章后面关于双向关联的讨论。 </p>
<p>下面的例子展示一个<tt class=literal>Part</tt>实体的map,把name作为关键字。( <tt class=literal>partName</tt> 是<tt class=literal>Part</tt>的持久化属性)。注意其中的基于公式的索引的用法。 </p>
<pre class=programlisting>&lt;map name="parts"
cascade="all"&gt;
&lt;key column="productId" not-null="true"/&gt;
&lt;map-key formula="partName"/&gt;
&lt;one-to-many class="Part"/&gt;
&lt;/map&gt;</pre>
</div>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=collections-advancedmappings></a>7.3.&nbsp;高级集合映射（Advanced collection mappings）</h2>
</div>
</div>
<div></div>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=collections-sorted></a>7.3.1.&nbsp;有序集合（Sorted collections）</h3>
</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"&gt;
&lt;key column="year_id"/&gt;
&lt;map-key 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="lower(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"&gt;
&lt;key column="year_id"/&gt;
&lt;map-key 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.createFilter( group.getUsers(), "order by this.name" ).list();</pre>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=collections-bidirectional></a>7.3.2.&nbsp;双向关联（Bidirectional associations）</h3>
</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>
<dd>
<p>Set或者bag值在一端, 单独值(非集合)在另外一端 </p>
<dt><span class=term>多对多（many-to-many）</span>
<dd>
<p>两端都是set或bag值 </p>
</dd></dl></div>
<p>&nbsp;</p>
<p>要建立一个双向的多对多关联，只需要映射两个many-to-many关联到同一个数据库表中，并再定义其中的一端为<span class=emphasis><em>inverse</em></span>(使用哪一端要根据你的选择，但它不能是一个索引集合)。 </p>
<p>这里有一个many-to-many的双向关联的例子;每一个category都可以有很多items,每一个items可以属于很多categories： </p>
<pre class=programlisting>&lt;class name="Category"&gt;
&lt;id name="id" column="CATEGORY_ID"/&gt;
...
&lt;bag name="items" table="CATEGORY_ITEM"&gt;
&lt;key column="CATEGORY_ID"/&gt;
&lt;many-to-many class="Item" column="ITEM_ID"/&gt;
&lt;/bag&gt;
&lt;/class&gt;
&lt;class name="Item"&gt;
&lt;id name="id" column="CATEGORY_ID"/&gt;
...
&lt;!-- inverse end --&gt;
&lt;bag name="categories" table="CATEGORY_ITEM" inverse="true"&gt;
&lt;key column="ITEM_ID"/&gt;
&lt;many-to-many class="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.persist(item);                   // The relationship won''t be saved!
session.persist(category);               // The relationship will be saved</pre>
<p>非反向端用于把内存中的表示保存到数据库中。 </p>
<p>要建立一个一对多的双向关联，你可以通过把一个一对多关联，作为一个多对一关联映射到到同一张表的字段上，并且在"多"的那一端定义<tt class=literal>inverse="true"</tt>。 </p>
<pre class=programlisting>&lt;class name="Parent"&gt;
&lt;id name="id" column="parent_id"/&gt;
....
&lt;set name="children" inverse="true"&gt;
&lt;key column="parent_id"/&gt;
&lt;one-to-many class="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="Parent"
column="parent_id"
not-null="true"/&gt;
&lt;/class&gt;</pre>
<p>在&#8220;一&#8221;这一端定义<tt class=literal>inverse="true"</tt>不会影响级联操作，二者是正交的概念！ </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=collections-ternary></a>7.3.3.&nbsp;三重关联（Ternary associations）</h3>
</div>
</div>
<div></div>
</div>
<p>有三种可能的途径来映射一个三重关联。第一种是使用一个<tt class=literal>Map</tt>，把一个关联作为其索引： </p>
<pre class=programlisting>&lt;map name="contracts"&gt;
&lt;key column="employer_id" not-null="true"/&gt;
&lt;map-key-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"&gt;
&lt;key column="incoming_node_id"/&gt;
&lt;map-key-many-to-many column="outgoing_node_id" class="Node"/&gt;
&lt;many-to-many column="connection_id" class="Connection"/&gt;
&lt;/map&gt;</pre>
<p>第二种方法是简单的把关联重新建模为一个实体类。这使我们最经常使用的方法。 </p>
<p>最后一种选择是使用复合元素，我们会在后面讨论 </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=collections-idbag></a>7.3.4.&nbsp;<tt class=literal>使用&lt;idbag&gt;</tt></h3>
</div>
</div>
<div></div>
</div>
<p>如果你完全信奉我们对于&#8220;联合主键（composite keys）是个坏东西&#8221;，和&#8220;实体应该使用（无机的）自己生成的代用标识符（surrogate keys）&#8221;的观点，也许你会感到有一些奇怪，我们目前为止展示的多对多关联和值集合都是映射成为带有联合主键的表的！现在，这一点非常值得争辩；看上去一个单纯的关联表并不能从代用标识符中获得什么好处（虽然使用组合值的集合<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"&gt;
&lt;collection-id column="ID" type="long"&gt;
&lt;generator class="sequence"/&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>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=collections-example></a>7.4.&nbsp;集合例子（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>Child</tt>的实例集合。如果每一个子实例至多有一个父实例, 那么最自然的映射是一个one-to-many的关联关系： </p>
<pre class=programlisting>&lt;hibernate-mapping&gt;
&lt;class name="Parent"&gt;
&lt;id name="id"&gt;
&lt;generator class="sequence"/&gt;
&lt;/id&gt;
&lt;set name="children"&gt;
&lt;key column="parent_id"/&gt;
&lt;one-to-many class="Child"/&gt;
&lt;/set&gt;
&lt;/class&gt;
&lt;class name="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="Parent"&gt;
&lt;id name="id"&gt;
&lt;generator class="sequence"/&gt;
&lt;/id&gt;
&lt;set name="children" inverse="true"&gt;
&lt;key column="parent_id"/&gt;
&lt;one-to-many class="Child"/&gt;
&lt;/set&gt;
&lt;/class&gt;
&lt;class name="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="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>另外，如果你绝对坚持这个关联应该是单向的，你可以对<tt class=literal>&lt;key&gt;</tt>映射声明<tt class=literal>NOT NULL</tt>约束： </p>
<pre class=programlisting>&lt;hibernate-mapping&gt;
&lt;class name="Parent"&gt;
&lt;id name="id"&gt;
&lt;generator class="sequence"/&gt;
&lt;/id&gt;
&lt;set name="children"&gt;
&lt;key column="parent_id" not-null="true"/&gt;
&lt;one-to-many class="Child"/&gt;
&lt;/set&gt;
&lt;/class&gt;
&lt;class name="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>另外一方面,如果一个子实例可能有多个父实例, 那么就应该使用many-to-many关联： </p>
<pre class=programlisting>&lt;hibernate-mapping&gt;
&lt;class name="Parent"&gt;
&lt;id name="id"&gt;
&lt;generator class="sequence"/&gt;
&lt;/id&gt;
&lt;set name="children" table="childset"&gt;
&lt;key column="parent_id"/&gt;
&lt;many-to-many class="Child" column="child_id"/&gt;
&lt;/set&gt;
&lt;/class&gt;
&lt;class name="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>
<img src ="http://www.blogjava.net/19851985lili/aggbug/108139.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-04-03 10:32 <a href="http://www.blogjava.net/19851985lili/articles/108139.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对象/关系数据库映射基础</title><link>http://www.blogjava.net/19851985lili/articles/108133.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 03 Apr 2007 02:16:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/108133.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/108133.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/108133.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/108133.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/108133.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;&nbsp;对象和关系数据库之间的映射通常是用一个XML文档(XML document)来定义的。这个映射文档被设计为易读的， 并且可以手工修改。映射语言是以Java为中心，这意味着映射文档是按照持久化类的定义来创建的， 而非表的定义。 请注意，虽然很多Hibernate用户选择手写XML映射文档，但也有一些工具可以用来生成映射文档， 包括XDocl...&nbsp;&nbsp;<a href='http://www.blogjava.net/19851985lili/articles/108133.html'>阅读全文</a><img src ="http://www.blogjava.net/19851985lili/aggbug/108133.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-04-03 10:16 <a href="http://www.blogjava.net/19851985lili/articles/108133.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HIBERNATE  配置 </title><link>http://www.blogjava.net/19851985lili/articles/108128.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 03 Apr 2007 01:52:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/108128.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/108128.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/108128.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/108128.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/108128.html</trackback:ping><description><![CDATA[<div class=titlepage>
<div>
<div>
<h2 class=title><a name=session-configuration></a>第&nbsp;4&nbsp;章&nbsp; 配置 </h2>
</div>
</div>
<div></div>
</div>
<p>由于Hibernate是为了能在各种不同环境下工作而设计的, 因此存在着大量的配置参数. 幸运的是多数配置参数都 有比较直观的默认值, 并有随Hibernate一同分发的配置样例<tt class=literal>hibernate.properties</tt> (位于<tt class=literal>etc/</tt>)来展示各种配置选项. 所需做的仅仅是将这个样例文件复制到类路径 (classpath)下做一些自定义的修改. </p>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=configuration-programmatic></a>4.1.&nbsp; 可编程的配置方式 </h2>
</div>
</div>
<div></div>
</div>
<p>一个<tt class=literal>org.hibernate.cfg.Configuration</tt>实例代表了一个应用程序中Java类型 到SQL数据库映射的完整集合. <tt class=literal>Configuration</tt>被用来构建一个(不可变的 (immutable))<tt class=literal>SessionFactory</tt>. 映射定义则由不同的XML映射定义文件编译而来. </p>
<p>你可以直接实例化<tt class=literal>Configuration</tt>来获取一个实例，并为它指定XML映射定义 文件. 如果映射定 义文件在类路径(classpath)中, 请使用<tt class=literal>addResource()</tt>: </p>
<pre class=programlisting>Configuration cfg = new Configuration()
.addResource("Item.hbm.xml")
.addResource("Bid.hbm.xml");</pre>
<p>一个替代方法（有时是更好的选择）是，指定被映射的类，让Hibernate帮你寻找映射定义文件: </p>
<pre class=programlisting>Configuration cfg = new Configuration()
.addClass(org.hibernate.auction.Item.class)
.addClass(org.hibernate.auction.Bid.class);</pre>
<p>Hibernate将会在类路径(classpath)中寻找名字为 <tt class=literal>/org/hibernate/auction/Item.hbm.xml</tt>和 <tt class=literal>/org/hibernate/auction/Bid.hbm.xml</tt>映射定义文件. 这种方式消除了任何对文件名的硬编码(hardcoded). </p>
<p><tt class=literal>Configuration</tt>也允许你指定配置属性: </p>
<pre class=programlisting>Configuration cfg = new Configuration()
.addClass(org.hibernate.auction.Item.class)
.addClass(org.hibernate.auction.Bid.class)
.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect")
.setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test")
.setProperty("hibernate.order_updates", "true");</pre>
<p>当然这不是唯一的传递Hibernate配置属性的方式, 其他可选方式还包括: </p>
<div class=orderedlist>
<ol type=1 compact>
    <li>
    <p>传一个<tt class=literal>java.util.Properties</tt>实例给 <tt class=literal>Configuration.setProperties()</tt>. </p>
    <li>
    <p>将<tt class=literal>hibernate.properties</tt>放置在类路径(classpath)的根目录下 (root directory). </p>
    <li>
    <p>通过<tt class=literal>java -Dproperty=value</tt>来设置系统 (<tt class=literal>System</tt>)属性. </p>
    <li>
    <p>在<tt class=literal>hibernate.cfg.xml</tt>中加入元素 <tt class=literal>&lt;property&gt;</tt> (稍后讨论). </p>
    </li>
</ol>
</div>
<p>如果想尽快体验Hbernate, <tt class=literal>hibernate.properties</tt>是最简单的方式. </p>
<p><tt class=literal>Configuration</tt>实例是一个启动期间（startup-time）的对象, 一旦<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=configuration-sessionfactory></a>4.2.&nbsp; 获得SessionFactory </h2>
</div>
</div>
<div></div>
</div>
<p>当所有映射定义被<tt class=literal>Configuration</tt>解析后, 应用程序必须获得一个用于构造<tt class=literal>Session</tt>实例的工厂. 这个工厂将被应用程序的所有线程共享: </p>
<pre class=programlisting>SessionFactory sessions = cfg.buildSessionFactory();</pre>
<p>Hibernate允许你的应用程序创建多个<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=configuration-hibernatejdbc></a>4.3.&nbsp; JDBC连接 </h2>
</div>
</div>
<div></div>
</div>
<p>通常你希望<tt class=literal>SessionFactory</tt>来为你创建和缓存(pool)JDBC连接. 如果你采用这种方式, 只需要如下例所示那样，打开一个<tt class=literal>Session</tt>: </p>
<pre class=programlisting>Session session = sessions.openSession(); // open a new Session</pre>
<p>一旦你需要进行数据访问时, 就会从连接池(connection pool)获得一个JDBC连接. </p>
<p>为了使这种方式工作起来, 我们需要向Hibernate传递一些JDBC连接的属性. 所有Hibernate属性的名字和语义都在<tt class=literal>org.hibernate.cfg.Environment</tt>中定义. 我们现在将描述JDBC连接配置中最重要的设置. </p>
<p>如果你设置如下属性，Hibernate将使用<tt class=literal>java.sql.DriverManager</tt>来获得(和缓存)JDBC连接 : </p>
<div class=table><a name=d0e2044></a>
<p class=title><strong>表&nbsp;4.1.&nbsp; Hibernate JDBC属性 </strong></p>
<table summary="&#10;                Hibernate JDBC属性&#10;            " 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><span class=emphasis><em>jdbc驱动类</em></span></td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.connection.url</tt></td>
            <td><span class=emphasis><em>jdbc URL</em></span></td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.connection.username</tt></td>
            <td><span class=emphasis><em>数据库用户</em></span></td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.connection.password</tt></td>
            <td><span class=emphasis><em>数据库用户密码</em></span></td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.connection.pool_size</tt></td>
            <td><span class=emphasis><em>连接池容量上限数目</em></span></td>
        </tr>
    </tbody>
</table>
</div>
<p>但Hibernate自带的连接池算法相当不成熟. 它只是为了让你快些上手<span class=emphasis><em>，不适合用于产品系统</em></span>或性能测试中。 出于最佳性能和稳定性考虑你应该使用第三方的连接池。只需要连接池的特定设置替换 <tt class=literal>hibernate.connection.pool_size</tt>。这将关闭Hibernate自带的连接池. 例如, 你可能会想用C3P0. </p>
<p>C3P0是一个随Hibernate一同分发的开源的JDBC连接池, 它位于<tt class=literal>lib</tt>目录下。 如果你设置了<tt class=literal>hibernate.c3p0.*</tt>相关的属性, Hibernate将使用 <tt class=literal>C3P0ConnectionProvider</tt>来缓存JDBC连接. 如果你更原意使用Proxool, 请参考发 行包中的<tt class=literal>hibernate.properties</tt>并到Hibernate网站获取更多的信息. </p>
<p>这是一个使用C3P0的<tt class=literal>hibernate.properties</tt>样例文件: </p>
<a name=c3p0-configuration></a>
<pre class=programlisting>hibernate.connection.driver_class = org.postgresql.Driver
hibernate.connection.url = jdbc:postgresql://localhost/mydatabase
hibernate.connection.username = myuser
hibernate.connection.password = secret
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.timeout=1800
hibernate.c3p0.max_statements=50
hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect</pre>
<p>为了能在应用程序服务器(application server)中使用Hibernate, 你应当总是将Hibernate 配置成注册在JNDI中的<tt class=literal>Datasource</tt>处获得连接，你至少需要设置下列属性中的一个: </p>
<div class=table><a name=d0e2126></a>
<p class=title><strong>表&nbsp;4.2.&nbsp; Hibernate数据源属性 </strong></p>
<table summary="&#10;                Hibernate数据源属性&#10;            " border=1>
    <colgroup>
    <col>
    <col></colgroup>
    <thead>
        <tr>
            <th>属性名 </th>
            <th>用途 </th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><tt class=literal>hibernate.connection.datasource</tt></td>
            <td><span class=emphasis><em>数据源JNDI名字</em></span></td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.jndi.url</tt></td>
            <td><span class=emphasis><em>JNDI提供者的URL</em></span> (可选) </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.jndi.class</tt></td>
            <td><span class=emphasis><em>JNDI <tt class=literal>InitialContextFactory</tt>类</em></span> (可选) </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.connection.username</tt></td>
            <td><span class=emphasis><em>数据库用户</em></span> (可选) </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.connection.password</tt></td>
            <td><span class=emphasis><em>数据库用户密码</em></span> (可选) </td>
        </tr>
    </tbody>
</table>
</div>
<p>这里有一个使用应用程序服务器JNDI数据源的<tt class=literal>hibernate.properties</tt>样例文件: </p>
<pre class=programlisting>hibernate.connection.datasource = java:/comp/env/jdbc/test
hibernate.transaction.factory_class = \
org.hibernate.transaction.JTATransactionFactory
hibernate.transaction.manager_lookup_class = \
org.hibernate.transaction.JBossTransactionManagerLookup
hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect</pre>
<p>从JNDI数据源获得的JDBC连接将自动参与应用程序服务器中容器管理的事务(container-managed transactions)中去. </p>
<p>任何连接(connection)配置属性的属性名要以"<tt class=literal>hibernate.connnection</tt>"前缀开头. 例如, 你可能会使用<tt class=literal>hibernate.connection.charSet</tt>来指定<tt class=literal>charSet</tt>. </p>
<p>通过实现<tt class=literal>org.hibernate.connection.ConnectionProvider</tt>接口，你可以定义属于 你自己的获得JDBC连接的插件策略。通过设置<tt class=literal>hibernate.connection.provider_class</tt>， 你可以选择一个自定义的实现. </p>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=configuration-optional></a>4.4.&nbsp; 可选的配置属性 </h2>
</div>
</div>
<div></div>
</div>
<p>有大量属性能用来控制Hibernate在运行期的行为. 它们都是可选的, 并拥有适当的默认值. </p>
<p><span class=emphasis><em>警告: 其中一些属性是"系统级(system-level)的".</em></span> 系统级属性可以通过<tt class=literal>java -Dproperty=value</tt>或 <tt class=literal>hibernate.properties</tt>来设置, 而<span class=emphasis><em>不能</em></span>用上面描述的其他方法来设置. </p>
<div class=table><a name=configuration-optional-properties></a>
<p class=title><strong>表&nbsp;4.3.&nbsp; Hibernate配置属性 </strong></p>
<table summary="&#10;                Hibernate配置属性&#10;            " border=1>
    <colgroup>
    <col>
    <col></colgroup>
    <thead>
        <tr>
            <th>属性名 </th>
            <th>用途 </th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><tt class=literal>hibernate.dialect</tt></td>
            <td>一个Hibernate <tt class=literal>Dialect</tt>类名允许Hibernate针对特定的关系数据库生成优化的SQL.
            <p><span class=strong>取值</span> <tt class=literal>full.classname.of.Dialect</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.show_sql</tt></td>
            <td>输出所有SQL语句到控制台.
            <p><span class=strong>取值</span> <tt class=literal>true</tt> | <tt class=literal>false</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.default_schema</tt></td>
            <td>在生成的SQL中, 将给定的schema/tablespace附加于非全限定名的表名上.
            <p><span class=strong>取值</span> <tt class=literal>SCHEMA_NAME</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.default_catalog</tt></td>
            <td>在生成的SQL中, 将给定的catalog附加于没全限定名的表名上.
            <p><span class=strong>取值</span> <tt class=literal>CATALOG_NAME</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.session_factory_name</tt></td>
            <td><tt class=literal>SessionFactory</tt>创建后，将自动使用这个名字绑定到JNDI中.
            <p><span class=strong>取值</span> <tt class=literal>jndi/composite/name</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.max_fetch_depth</tt></td>
            <td>为单向关联(一对一, 多对一)的外连接抓取（outer join fetch）树设置最大深度. 值为<tt class=literal>0</tt>意味着将关闭默认的外连接抓取.
            <p><span class=strong>取值</span> 建议在<tt class=literal>0</tt>到<tt class=literal>3</tt>之间取值 </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.default_batch_fetch_size</tt></td>
            <td>为Hibernate关联的批量抓取设置默认数量.
            <p><span class=strong>取值</span> 建议的取值为<tt class=literal>4</tt>, <tt class=literal>8</tt>, 和<tt class=literal>16</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.default_entity_mode</tt></td>
            <td>为由这个<tt class=literal>SessionFactory</tt>打开的所有Session指定默认的实体表现模式.
            <p><span class=strong>取值</span> <tt class=literal>dynamic-map</tt>, <tt class=literal>dom4j</tt>, <tt class=literal>pojo</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.order_updates</tt></td>
            <td>强制Hibernate按照被更新数据的主键，为SQL更新排序。这么做将减少在高并发系统中事务的死锁。
            <p><span class=strong>取值</span> <tt class=literal>true</tt> | <tt class=literal>false</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.generate_statistics</tt></td>
            <td>如果开启, Hibernate将收集有助于性能调节的统计数据.
            <p><span class=strong>取值</span> <tt class=literal>true</tt> | <tt class=literal>false</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.use_identifer_rollback</tt></td>
            <td>如果开启, 在对象被删除时生成的标识属性将被重设为默认值.
            <p><span class=strong>取值</span> <tt class=literal>true</tt> | <tt class=literal>false</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.use_sql_comments</tt></td>
            <td>如果开启, Hibernate将在SQL中生成有助于调试的注释信息, 默认值为<tt class=literal>false</tt>.
            <p><span class=strong>取值</span> <tt class=literal>true</tt> | <tt class=literal>false</tt> </p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<div class=table><a name=configuration-jdbc-properties></a>
<p class=title><strong>表&nbsp;4.4.&nbsp; Hibernate JDBC和连接(connection)属性 </strong></p>
<table summary="&#10;                Hibernate JDBC和连接(connection)属性&#10;            " border=1>
    <colgroup>
    <col>
    <col></colgroup>
    <thead>
        <tr>
            <th>属性名 </th>
            <th>用途 </th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><tt class=literal>hibernate.jdbc.fetch_size</tt></td>
            <td>非零值，指定JDBC抓取数量的大小 (调用<tt class=literal>Statement.setFetchSize()</tt>). </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.jdbc.batch_size</tt></td>
            <td>非零值，允许Hibernate使用JDBC2的批量更新.
            <p><span class=strong>取值</span> 建议取<tt class=literal>5</tt>到<tt class=literal>30</tt>之间的值 </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.jdbc.batch_versioned_data</tt></td>
            <td>如果你想让你的JDBC驱动从<tt class=literal>executeBatch()</tt>返回正确的行计数 , 那么将此属性设为<tt class=literal>true</tt>(开启这个选项通常是安全的). 同时，Hibernate将为自动版本化的数据使用批量DML. 默认值为<tt class=literal>false</tt>.
            <p><span class=strong>eg.</span> <tt class=literal>true</tt> | <tt class=literal>false</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.jdbc.factory_class</tt></td>
            <td>选择一个自定义的<tt class=literal>Batcher</tt>. 多数应用程序不需要这个配置属性.
            <p><span class=strong>eg.</span> <tt class=literal>classname.of.Batcher</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.jdbc.use_scrollable_resultset</tt></td>
            <td>允许Hibernate使用JDBC2的可滚动结果集. 只有在使用用户提供的JDBC连接时，这个选项才是必要的, 否则Hibernate会使用连接的元数据.
            <p><span class=strong>取值</span> <tt class=literal>true</tt> | <tt class=literal>false</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.jdbc.use_streams_for_binary</tt></td>
            <td>在JDBC读写<tt class=literal>binary (二进制)</tt>或<tt class=literal>serializable (可序列化)</tt> 的类型时使用流(stream)(系统级属性).
            <p><span class=strong>取值</span> <tt class=literal>true</tt> | <tt class=literal>false</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.jdbc.use_get_generated_keys</tt></td>
            <td>在数据插入数据库之后，允许使用JDBC3 <tt class=literal>PreparedStatement.getGeneratedKeys()</tt> 来获取数据库生成的key(键)。需要JDBC3+驱动和JRE1.4+, 如果你的数据库驱动在使用Hibernate的标 识生成器时遇到问题，请将此值设为false. 默认情况下将使用连接的元数据来判定驱动的能力.
            <p><span class=strong>取值</span> <tt class=literal>true|false</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.connection.provider_class</tt></td>
            <td>自定义<tt class=literal>ConnectionProvider</tt>的类名, 此类用来向Hibernate提供JDBC连接.
            <p><span class=strong>取值</span> <tt class=literal>classname.of.ConnectionProvider</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.connection.isolation</tt></td>
            <td>设置JDBC事务隔离级别. 查看<tt class=literal>java.sql.Connection</tt>来了解各个值的具体意义, 但请注意多数数据库都不支持所有的隔离级别.
            <p><span class=strong>取值</span> <tt class=literal>1, 2, 4, 8</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.connection.autocommit</tt></td>
            <td>允许被缓存的JDBC连接开启自动提交(autocommit) (不建议).
            <p><span class=strong>取值</span> <tt class=literal>true</tt> | <tt class=literal>false</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.connection.release_mode</tt></td>
            <td>指定Hibernate在何时释放JDBC连接. 默认情况下,直到Session被显式关闭或被断开连接时,才会释放JDBC连接. 对于应用程序服务器的JTA数据源, 你应当使用<tt class=literal>after_statement</tt>, 这样在每次JDBC调用后，都会主动的释放连接. 对于非JTA的连接, 使用<tt class=literal>after_transaction</tt>在每个事务结束时释放连接是合理的. <tt class=literal>auto</tt>将为JTA和CMT事务策略选择<tt class=literal>after_statement</tt>, 为JDBC事务策略选择<tt class=literal>after_transaction</tt>.
            <p><span class=strong>取值</span> <tt class=literal>on_close</tt> | <tt class=literal>after_transaction</tt> | <tt class=literal>after_statement</tt> | <tt class=literal>auto</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.connection.<span class=emphasis><em>&lt;propertyName&gt;</em></span></tt></td>
            <td>将JDBC属性<tt class=literal>propertyName</tt>传递到<tt class=literal>DriverManager.getConnection()</tt>中去. </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.jndi.<span class=emphasis><em>&lt;propertyName&gt;</em></span></tt></td>
            <td>将属性<tt class=literal>propertyName</tt>传递到JNDI <tt class=literal>InitialContextFactory</tt>中去. </td>
        </tr>
    </tbody>
</table>
</div>
<div class=table><a name=configuration-cache-properties></a>
<p class=title><strong>表&nbsp;4.5.&nbsp; Hibernate缓存属性 </strong></p>
<table summary="&#10;                Hibernate缓存属性&#10;            " border=1>
    <colgroup>
    <col>
    <col></colgroup>
    <thead>
        <tr>
            <th>属性名 </th>
            <th>用途 </th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><tt class=literal>hibernate.cache.provider_class</tt></td>
            <td>自定义的<tt class=literal>CacheProvider</tt>的类名.
            <p><span class=strong>取值</span> <tt class=literal>classname.of.CacheProvider</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.cache.use_minimal_puts</tt></td>
            <td>以频繁的读操作为代价, 优化二级缓存来最小化写操作. 在Hibernate3中，这个设置对的集群缓存非常有用, 对集群缓存的实现而言，默认是开启的.
            <p><span class=strong>取值</span> <tt class=literal>true|false</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.cache.use_query_cache</tt></td>
            <td>允许查询缓存, 个别查询仍然需要被设置为可缓存的.
            <p><span class=strong>取值</span> <tt class=literal>true|false</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.cache.use_second_level_cache</tt></td>
            <td>能用来完全禁止使用二级缓存. 对那些在类的映射定义中指定<tt class=literal>&lt;cache&gt;</tt>的类，会默认开启二级缓存.
            <p><span class=strong>取值</span> <tt class=literal>true|false</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.cache.query_cache_factory</tt></td>
            <td>自定义的实现<tt class=literal>QueryCache</tt>接口的类名, 默认为内建的<tt class=literal>StandardQueryCache</tt>.
            <p><span class=strong>取值</span> <tt class=literal>classname.of.QueryCache</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.cache.region_prefix</tt></td>
            <td>二级缓存区域名的前缀.
            <p><span class=strong>取值</span> <tt class=literal>prefix</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.cache.use_structured_entries</tt></td>
            <td>强制Hibernate以更人性化的格式将数据存入二级缓存.
            <p><span class=strong>取值</span> <tt class=literal>true|false</tt> </p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<div class=table><a name=configuration-transaction-properties></a>
<p class=title><strong>表&nbsp;4.6.&nbsp; Hibernate事务属性 </strong></p>
<table summary="&#10;                Hibernate事务属性&#10;            " border=1>
    <colgroup>
    <col>
    <col></colgroup>
    <thead>
        <tr>
            <th>属性名 </th>
            <th>用途 </th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><tt class=literal>hibernate.transaction.factory_class</tt></td>
            <td>一个<tt class=literal>TransactionFactory</tt>的类名, 用于Hibernate <tt class=literal>Transaction</tt> API (默认为<tt class=literal>JDBCTransactionFactory</tt>).
            <p><span class=strong>取值</span> <tt class=literal>classname.of.TransactionFactory</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>jta.UserTransaction</tt></td>
            <td>一个JNDI名字，被<tt class=literal>JTATransactionFactory</tt>用来从应用服务器获取JTA <tt class=literal>UserTransaction</tt>.
            <p><span class=strong>取值</span> <tt class=literal>jndi/composite/name</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.transaction.manager_lookup_class</tt></td>
            <td>一个<tt class=literal>TransactionManagerLookup</tt>的类名 - 当使用JVM级缓存，或在JTA环境中使用hilo生成器的时候需要该类.
            <p><span class=strong>取值</span> <tt class=literal>classname.of.TransactionManagerLookup</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.transaction.flush_before_completion</tt></td>
            <td>如果开启, session在事务完成后将被自动清洗(flush). (在Hibernate和CMT一起使用时很有用.)
            <p><span class=strong>取值</span> <tt class=literal>true</tt> | <tt class=literal>false</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.transaction.auto_close_session</tt></td>
            <td>如果开启, session在事务完成后将被自动关闭. (在Hibernate和CMT一起使用时很有用.)
            <p><span class=strong>取值</span> <tt class=literal>true</tt> | <tt class=literal>false</tt> </p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<div class=table><a name=configuration-misc-properties></a>
<p class=title><strong>表&nbsp;4.7.&nbsp; 其他属性 </strong></p>
<table summary="&#10;                其他属性&#10;            " border=1>
    <colgroup>
    <col>
    <col></colgroup>
    <thead>
        <tr>
            <th>属性名 </th>
            <th>用途 </th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><tt class=literal>hibernate.query.factory_class</tt></td>
            <td>选择HQL解析器的实现.
            <p><span class=strong>取值</span> <tt class=literal>org.hibernate.hql.ast.ASTQueryTranslatorFactory</tt> or <tt class=literal>org.hibernate.hql.classic.ClassicQueryTranslatorFactory</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.query.substitutions</tt></td>
            <td>将Hibernate查询中的符号映射到SQL查询中的符号 (符号可能是函数名或常量名字).
            <p><span class=strong>取值</span> <tt class=literal>hqlLiteral=SQL_LITERAL, hqlFunction=SQLFUNC</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.hbm2ddl.auto</tt></td>
            <td>在<tt class=literal>SessionFactory</tt>创建时，自动将数据库schema的DDL导出到数据库. 使用 <tt class=literal>create-drop</tt>时,在显式关闭<tt class=literal>SessionFactory</tt>时，将drop掉数据库schema.
            <p><span class=strong>取值</span> <tt class=literal>update</tt> | <tt class=literal>create</tt> | <tt class=literal>create-drop</tt> </p>
            </td>
        </tr>
        <tr>
            <td><tt class=literal>hibernate.cglib.use_reflection_optimizer</tt></td>
            <td>开启CGLIB来替代运行时反射机制(系统级属性). 反射机制有时在除错时比较有用. 注意即使关闭这个优化, Hibernate还是需要CGLIB. 你不能在<tt class=literal>hibernate.cfg.xml</tt>中设置此属性.
            <p><span class=strong>取值</span> <tt class=literal>true</tt> | <tt class=literal>false</tt> </p>
            </td>
        </tr>
    </tbody>
</table>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=configuration-optional-dialects></a>4.4.1.&nbsp; SQL方言 </h3>
</div>
</div>
<div></div>
</div>
<p>你应当总是为你的数据库属性<tt class=literal>hibernate.dialect</tt>设置正确的 <tt class=literal>org.hibernate.dialect.Dialect</tt>子类. 如果你指定一种方言, Hibernate将为上面列出的一些属性使用合理的默认值, 为你省去了手工指定它们的功夫. </p>
<div class=table><a name=sql-dialects></a>
<p class=title><strong>表&nbsp;4.8.&nbsp; Hibernate SQL方言 (<tt class=literal>hibernate.dialect</tt>) </strong></p>
<table summary="&#10;                    Hibernate SQL方言 (hibernate.dialect)&#10;                " border=1>
    <colgroup>
    <col>
    <col></colgroup>
    <thead>
        <tr>
            <th>RDBMS</th>
            <th>方言 </th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>DB2</td>
            <td><tt class=literal>org.hibernate.dialect.DB2Dialect</tt></td>
        </tr>
        <tr>
            <td>DB2 AS/400</td>
            <td><tt class=literal>org.hibernate.dialect.DB2400Dialect</tt></td>
        </tr>
        <tr>
            <td>DB2 OS390</td>
            <td><tt class=literal>org.hibernate.dialect.DB2390Dialect</tt></td>
        </tr>
        <tr>
            <td>PostgreSQL</td>
            <td><tt class=literal>org.hibernate.dialect.PostgreSQLDialect</tt></td>
        </tr>
        <tr>
            <td>MySQL</td>
            <td><tt class=literal>org.hibernate.dialect.MySQLDialect</tt></td>
        </tr>
        <tr>
            <td>MySQL with InnoDB</td>
            <td><tt class=literal>org.hibernate.dialect.MySQLInnoDBDialect</tt></td>
        </tr>
        <tr>
            <td>MySQL with MyISAM</td>
            <td><tt class=literal>org.hibernate.dialect.MySQLMyISAMDialect</tt></td>
        </tr>
        <tr>
            <td>Oracle (any version)</td>
            <td><tt class=literal>org.hibernate.dialect.OracleDialect</tt></td>
        </tr>
        <tr>
            <td>Oracle 9i/10g</td>
            <td><tt class=literal>org.hibernate.dialect.Oracle9Dialect</tt></td>
        </tr>
        <tr>
            <td>Sybase</td>
            <td><tt class=literal>org.hibernate.dialect.SybaseDialect</tt></td>
        </tr>
        <tr>
            <td>Sybase Anywhere</td>
            <td><tt class=literal>org.hibernate.dialect.SybaseAnywhereDialect</tt></td>
        </tr>
        <tr>
            <td>Microsoft SQL Server</td>
            <td><tt class=literal>org.hibernate.dialect.SQLServerDialect</tt></td>
        </tr>
        <tr>
            <td>SAP DB</td>
            <td><tt class=literal>org.hibernate.dialect.SAPDBDialect</tt></td>
        </tr>
        <tr>
            <td>Informix</td>
            <td><tt class=literal>org.hibernate.dialect.InformixDialect</tt></td>
        </tr>
        <tr>
            <td>HypersonicSQL</td>
            <td><tt class=literal>org.hibernate.dialect.HSQLDialect</tt></td>
        </tr>
        <tr>
            <td>Ingres</td>
            <td><tt class=literal>org.hibernate.dialect.IngresDialect</tt></td>
        </tr>
        <tr>
            <td>Progress</td>
            <td><tt class=literal>org.hibernate.dialect.ProgressDialect</tt></td>
        </tr>
        <tr>
            <td>Mckoi SQL</td>
            <td><tt class=literal>org.hibernate.dialect.MckoiDialect</tt></td>
        </tr>
        <tr>
            <td>Interbase</td>
            <td><tt class=literal>org.hibernate.dialect.InterbaseDialect</tt></td>
        </tr>
        <tr>
            <td>Pointbase</td>
            <td><tt class=literal>org.hibernate.dialect.PointbaseDialect</tt></td>
        </tr>
        <tr>
            <td>FrontBase</td>
            <td><tt class=literal>org.hibernate.dialect.FrontbaseDialect</tt></td>
        </tr>
        <tr>
            <td>Firebird</td>
            <td><tt class=literal>org.hibernate.dialect.FirebirdDialect</tt></td>
        </tr>
    </tbody>
</table>
</div>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=configuration-optional-outerjoin></a>4.4.2.&nbsp; 外连接抓取(Outer Join Fetching) </h3>
</div>
</div>
<div></div>
</div>
<p>如果你的数据库支持ANSI, Oracle或Sybase风格的外连接, <span class=emphasis><em>外连接抓取</em></span>常能通过限制往返数据库次数 (更多的工作交由数据库自己来完成)来提高效率. 外连接允许在单个<tt class=literal>SELECT</tt>SQL语句中， 通过many-to-one, one-to-many, many-to-many和one-to-one关联获取连接对象的整个对象图. </p>
<p>将<tt class=literal>hibernate.max_fetch_depth</tt>设为<tt class=literal>0</tt>能在<span class=emphasis><em>全局</em></span> 范围内禁止外连接抓取. 设为<tt class=literal>1</tt>或更高值能启用one-to-one和many-to-oneouter关联的外连接抓取, 它们通过 <tt class=literal>fetch="join"</tt>来映射. </p>
<p>参见<a title="20.1.&nbsp;&#10;&#9;&#10;&#9;&#9;&#9;抓取策略(Fetching strategies)&#10;&#9;&#9;" href="file:///E:/_DataBank/_JavaHelp/Hibernate参考文档/html/performance.html#performance-fetching" tppabs="http://www.hibernate.org/hib_docs/v3/reference/zh-cn/html/performance.html#performance-fetching"><u><font color=#0000ff>第&nbsp;20.1&nbsp;节 &#8220; 抓取策略(Fetching strategies) &#8221;</font></u></a>获得更多信息. </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=configuration-optional-binarystreams></a>4.4.3.&nbsp; 二进制流 (Binary Streams) </h3>
</div>
</div>
<div></div>
</div>
<p>Oracle限制那些通过JDBC驱动传输的<tt class=literal>字节</tt>数组的数目. 如果你希望使用<tt class=literal>二进值 (binary)</tt>或 <tt class=literal>可序列化的 (serializable)</tt>类型的大对象, 你应该开启 <tt class=literal>hibernate.jdbc.use_streams_for_binary</tt>属性. <span class=emphasis><em>这是系统级属性.</em></span> </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=configuration-optional-cacheprovider></a>4.4.4.&nbsp; 二级缓存与查询缓存 </h3>
</div>
</div>
<div></div>
</div>
<p>以<tt class=literal>hibernate.cache</tt>为前缀的属性允许你在Hibernate中，使用进程或群集范围内的二级缓存系统. 参见<a title="20.2.&nbsp;二级缓存（The Second Level Cache）&#10;&#9;&#9;" href="file:///E:/_DataBank/_JavaHelp/Hibernate参考文档/html/performance.html#performance-cache" tppabs="http://www.hibernate.org/hib_docs/v3/reference/zh-cn/html/performance.html#performance-cache"><u><font color=#0000ff>第&nbsp;20.2&nbsp;节 &#8220;二级缓存（The Second Level Cache） &#8221;</font></u></a>获取更多的详情. </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=configuration-optional-querysubstitution></a>4.4.5.&nbsp; 查询语言中的替换 </h3>
</div>
</div>
<div></div>
</div>
<p>你可以使用<tt class=literal>hibernate.query.substitutions</tt>在Hibernate中定义新的查询符号. 例如: </p>
<pre class=programlisting>hibernate.query.substitutions true=1, false=0</pre>
<p>将导致符号<tt class=literal>true</tt>和<tt class=literal>false</tt>在生成的SQL中被翻译成整数常量. </p>
<pre class=programlisting>hibernate.query.substitutions toLowercase=LOWER</pre>
<p>将允许你重命名SQL中的<tt class=literal>LOWER</tt>函数. </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=configuration-optional-statistics></a>4.4.6.&nbsp; Hibernate的统计(statistics)机制 </h3>
</div>
</div>
<div></div>
</div>
<p>如果你开启<tt class=literal>hibernate.generate_statistics</tt>, 那么当你通过 <tt class=literal>SessionFactory.getStatistics()</tt>调整正在运行的系统时，Hibernate将导出大量有用的数据. Hibernate甚至能被配置成通过JMX导出这些统计信息. 参考<tt class=literal>org.hibernate.stats</tt>中接口的Javadoc，以获得更多信息. </p>
</div>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=configuration-logging></a>4.5.&nbsp; 日志 </h2>
</div>
</div>
<div></div>
</div>
<p>Hibernate使用Apache commons-logging来为各种事件记录日志. </p>
<p>commons-logging将直接输出到Apache Log4j(如果在类路径中包括<tt class=literal>log4j.jar</tt>)或 JDK1.4 logging (如果运行在JDK1.4或以上的环境下). 你可以从<tt class=literal>http://jakarta.apache.org</tt> 下载Log4j. 要使用Log4j，你需要将<tt class=literal>log4j.properties</tt>文件放置在类路径下, 随Hibernate 一同分发的样例属性文件在<tt class=literal>src/</tt>目录下. </p>
<p>我们强烈建议你熟悉一下Hibernate的日志消息. 在不失可读性的前提下， 我们做了很多工作，使Hibernate的日志可能地详细. 这是必要的查错利器. 最令人感兴趣的日志分类有如下这些: </p>
<div class=table><a name=log-categories></a>
<p class=title><strong>表&nbsp;4.9.&nbsp; Hibernate日志类别 </strong></p>
<table summary="&#10;                    Hibernate日志类别&#10;                " border=1>
    <colgroup>
    <col>
    <col></colgroup>
    <thead>
        <tr>
            <th>类别 </th>
            <th>功能 </th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><tt class=literal>org.hibernate.SQL</tt></td>
            <td>在所有SQL DML语句被执行时为它们记录日志 </td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.type</tt></td>
            <td>为所有JDBC参数记录日志 </td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.tool.hbm2ddl</tt></td>
            <td>在所有SQL DDL语句执行时为它们记录日志 </td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.pretty</tt></td>
            <td>在session清洗(flush)时，为所有与其关联的实体(最多20个)的状态记录日志 </td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.cache</tt></td>
            <td>为所有二级缓存的活动记录日志 </td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.transaction</tt></td>
            <td>为事务相关的活动记录日志 </td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.jdbc</tt></td>
            <td>为所有JDBC资源的获取记录日志 </td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.hql.ast</tt></td>
            <td>为HQL和SQL的自动状态转换和其他关于查询解析的信息记录日志 </td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.secure</tt></td>
            <td>为JAAS认证请求做日志 </td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate</tt></td>
            <td>为任何Hibernate相关信息做日志 (信息量较大, 但对查错非常有帮助) </td>
        </tr>
    </tbody>
</table>
</div>
<p>在使用Hibernate开发应用程序时, 你应当总是为<tt class=literal>org.hibernate.SQL</tt> 开启<tt class=literal>debug</tt>级别的日志记录,或者开启<tt class=literal>hibernate.show_sql</tt>属性来代替它。. </p>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=configuration-namingstrategy></a>4.6.&nbsp; 实现<tt class=literal>NamingStrategy</tt> </h2>
</div>
</div>
<div></div>
</div>
<p><tt class=literal>org.hibernate.cfg.NamingStrategy</tt>接口允许你为数据库中的对象和schema 元素指定一个&#8220;命名标准&#8221;. </p>
<p>你可能会提供一些通过Java标识生成数据库标识或将映射定义文件中"逻辑"表/列名处理成"物理"表/列名的规则. 这个特性有助于减少冗长的映射定义文件. </p>
<p>在加入映射定义前，你可以调用 <tt class=literal>Configuration.setNamingStrategy()</tt>指定一个不同的命名策略: </p>
<pre class=programlisting>SessionFactory sf = new Configuration()
.setNamingStrategy(ImprovedNamingStrategy.INSTANCE)
.addFile("Item.hbm.xml")
.addFile("Bid.hbm.xml")
.buildSessionFactory();</pre>
<p><tt class=literal>org.hibernate.cfg.ImprovedNamingStrategy</tt>是一个内建的命名策略, 对 一些应用程序而言，可能是非常有用的起点. </p>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=configuration-xmlconfig></a>4.7.&nbsp; XML配置文件 </h2>
</div>
</div>
<div></div>
</div>
<p>另一个配置方法是在<tt class=literal>hibernate.cfg.xml</tt>文件中指定一套完整的配置. 这个文件可以当成<tt class=literal>hibernate.properties</tt>的替代。 若两个文件同时存在，它将重载前者的属性. </p>
<p>XML配置文件被默认是放在<tt class=literal>CLASSPATH</tt>的根目录下. 这是一个例子: </p>
<p>&nbsp;</p>
<pre class=programlisting>&lt;?xml version='1.0' encoding='utf-8'?&gt;
&lt;!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"&gt;
&lt;hibernate-configuration&gt;
&lt;!-- 以/jndi/name绑定到JNDI的SessionFactory实例 --&gt;
&lt;session-factory
name="java:hibernate/SessionFactory"&gt;
&lt;!-- 属性 --&gt;
&lt;property name="connection.datasource"&gt;java:/comp/env/jdbc/MyDB&lt;/property&gt;
&lt;property name="dialect"&gt;org.hibernate.dialect.MySQLDialect&lt;/property&gt;
&lt;property name="show_sql"&gt;false&lt;/property&gt;
&lt;property name="transaction.factory_class"&gt;
org.hibernate.transaction.JTATransactionFactory
&lt;/property&gt;
&lt;property name="jta.UserTransaction"&gt;java:comp/UserTransaction&lt;/property&gt;
&lt;!-- 映射定义文件 --&gt;
&lt;mapping resource="org/hibernate/auction/Item.hbm.xml"/&gt;
&lt;mapping resource="org/hibernate/auction/Bid.hbm.xml"/&gt;
&lt;!-- 缓存设置 --&gt;
&lt;class-cache class="org.hibernate.auction.Item" usage="read-write"/&gt;
&lt;class-cache class="org.hibernate.auction.Bid" usage="read-only"/&gt;
&lt;collection-cache class="org.hibernate.auction.Item.bids" usage="read-write"/&gt;
&lt;/session-factory&gt;
&lt;/hibernate-configuration&gt;</pre>
<p>如你所见, 这个方法优势在于，在配置文件中指出了映射定义文件的名字. 一旦你需要调整Hibernate的缓存， <tt class=literal>hibernate.cfg.xml</tt>也是更方便. 注意，使用<tt class=literal>hibernate.properties</tt>还是 <tt class=literal>hibernate.cfg.xml</tt>完全是由你来决定, 除了上面提到的XML语法的优势之外, 两者是等价的. </p>
<p>使用XML配置，使得启动Hibernate变的异常简单, 如下所示，一行代码就可以搞定： </p>
<pre class=programlisting>SessionFactory sf = new Configuration().configure().buildSessionFactory();</pre>
<p>你可以使用如下代码来添加一个不同的XML配置文件 </p>
<pre class=programlisting>SessionFactory sf = new Configuration()
.configure("catdb.cfg.xml")
.buildSessionFactory();</pre>
</div>
<div class=sect1 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h2 class=title style="CLEAR: both"><a name=configuration-j2ee></a>4.8.&nbsp; J2EE应用程序服务器的集成 </h2>
</div>
</div>
<div></div>
</div>
<p>针对J2EE体系,Hibernate有如下几个集成的方面: </p>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p><span class=emphasis><em>容器管理的数据源(Container-managed datasources)</em></span>: Hibernate能通过容器管理由JNDI提供的JDBC连接. 通常, 特别是当处理多个数据源的分布式事务的时候, 由一个JTA兼容的<tt class=literal>TransactionManager</tt>和一个 <tt class=literal>ResourceManager</tt>来处理事务管理(CMT, 容器管理的事务). 当然你可以通过 编程方式来划分事务边界(BMT, Bean管理的事务). 或者为了代码的可移植性，你也也许会想使用可选的 Hibernate <tt class=literal>Transaction</tt> API. </p>
    </li>
</ul>
</div>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p><span class=emphasis><em>自动JNDI绑定</em></span>: Hibernate可以在启动后将 <tt class=literal>SessionFactory</tt>绑定到JNDI. </p>
    </li>
</ul>
</div>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p><span class=emphasis><em>JTA Session绑定:</em></span> 如果使用EJB, Hibernate <tt class=literal>Session</tt> 可以自动绑定到JTA事务作用的范围. 只需简单地从JNDI查找<tt class=literal>SessionFactory</tt>并获得当前的 <tt class=literal>Session</tt>. 当JTA事务完成时, 让Hibernate来处理 <tt class=literal>Session</tt>的清洗(flush)与关闭. 在EJB的部署描述符中事务边界是声明式的. </p>
    </li>
</ul>
</div>
<div class=itemizedlist>
<ul type=disc>
    <li>
    <p><span class=emphasis><em>JMX部署:</em></span> 如果你使用支持JMX应用程序服务器(如, JBoss AS), 那么你可以选择将Hibernate部署成托管MBean. 这将为你省去一行从<tt class=literal>Configuration</tt>构建<tt class=literal>SessionFactory</tt>的启动代码. 容器将启动你的<tt class=literal>HibernateService</tt>, 并完美地处理好服务间的依赖关系 (在Hibernate启动前，数据源必须是可用的等等). </p>
    </li>
</ul>
</div>
<p>如果应用程序服务器抛出"connection containment"异常, 根据你的环境，也许该将配置属性 <tt class=literal>hibernate.connection.release_mode</tt>设为<tt class=literal>after_statement</tt>. </p>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=configuration-optional-transactionstrategy></a>4.8.1.&nbsp; 事务策略配置 </h3>
</div>
</div>
<div></div>
</div>
<p>在你的架构中，Hibernate的<tt class=literal>Session</tt> API是独立于任何事务分界系统的. 如果你让Hibernate通过连接池直接使用JDBC, 你需要调用JDBC API来打开和关闭你的事务. 如果你运行在J2EE应用程序服务器中, 你也许想用Bean管理的事务并在需要的时候调用JTA API和<tt class=literal>UserTransaction</tt>. </p>
<p>为了让你的代码在两种(或其他)环境中可以移植，我们建议使用可选的Hibernate <tt class=literal>Transaction</tt> API, 它包装并隐藏了底层系统. 你必须通过设置Hibernate配置属性<tt class=literal>hibernate.transaction.factory_class</tt>来指定 一个<tt class=literal>Transaction</tt>实例的工厂类. </p>
<p>存在着三个标准(内建)的选择: </p>
<div class=variablelist>
<dl>
<dt><span class=term><tt class=literal>org.hibernate.transaction.JDBCTransactionFactory</tt></span>
<dd>
<p>委托给数据库(JDBC)事务（默认） </p>
<dt><span class=term><tt class=literal>org.hibernate.transaction.JTATransactionFactory</tt></span>
<dd>
<p>如果在上下文环境中存在运行着的事务(如, EJB会话Bean的方法), 则委托给容器管 理的事务, 否则，将启动一个新的事务，并使用Bean管理的事务. </p>
<dt><span class=term><tt class=literal>org.hibernate.transaction.CMTTransactionFactory</tt></span>
<dd>
<p>委托给容器管理的JTA事务 </p>
</dd></dl></div>
<p>你也可以定义属于你自己的事务策略 (如, 针对CORBA的事务服务) </p>
<p>Hibernate的一些特性 (即二级缓存, JTA与Session的自动绑定等等)需要访问在托管环境中的JTA <tt class=literal>TransactionManager</tt>. 由于J2EE没有标准化一个单一的机制,Hibernate在应用程序服务器中，你必须指定Hibernate如何获得<tt class=literal>TransactionManager</tt>的引用: </p>
<div class=table><a name=jtamanagerlookup></a>
<p class=title><strong>表&nbsp;4.10.&nbsp;JTA TransactionManagers</strong></p>
<table summary="JTA TransactionManagers" border=1>
    <colgroup>
    <col>
    <col></colgroup>
    <thead>
        <tr>
            <th>Transaction工厂类 </th>
            <th align=middle>应用程序服务器 </th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><tt class=literal>org.hibernate.transaction.JBossTransactionManagerLookup</tt></td>
            <td align=middle>JBoss</td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.transaction.WeblogicTransactionManagerLookup</tt></td>
            <td align=middle>Weblogic</td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.transaction.WebSphereTransactionManagerLookup</tt></td>
            <td align=middle>WebSphere</td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</tt></td>
            <td align=middle>WebSphere 6</td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.transaction.OrionTransactionManagerLookup</tt></td>
            <td align=middle>Orion</td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.transaction.ResinTransactionManagerLookup</tt></td>
            <td align=middle>Resin</td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.transaction.JOTMTransactionManagerLookup</tt></td>
            <td align=middle>JOTM</td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.transaction.JOnASTransactionManagerLookup</tt></td>
            <td align=middle>JOnAS</td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.transaction.JRun4TransactionManagerLookup</tt></td>
            <td align=middle>JRun4</td>
        </tr>
        <tr>
            <td><tt class=literal>org.hibernate.transaction.BESTransactionManagerLookup</tt></td>
            <td align=middle>Borland ES</td>
        </tr>
    </tbody>
</table>
</div>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=configuration-optional-jndi></a>4.8.2.&nbsp; JNDI绑定的<tt class=literal>SessionFactory</tt> </h3>
</div>
</div>
<div></div>
</div>
<p>与JNDI绑定的Hibernate的<tt class=literal>SessionFactory</tt>能简化工厂的查询，简化创建新的<tt class=literal>Session</tt>. 需要注意的是这与JNDI绑定<tt class=literal>Datasource</tt>没有关系, 它们只是恰巧用了相同的注册表! </p>
<p>如果你希望将<tt class=literal>SessionFactory</tt>绑定到一个JNDI的名字空间, 用属性<tt class=literal>hibernate.session_factory_name</tt>指定一个名字(如, <tt class=literal>java:hibernate/SessionFactory</tt>). 如果不设置这个属性, <tt class=literal>SessionFactory</tt>将不会被绑定到JNDI中. (在以只读JNDI为默认实现的环境中，这个设置尤其有用, 如Tomcat.) </p>
<p>在将<tt class=literal>SessionFactory</tt>绑定至JNDI时, Hibernate将使用<tt class=literal>hibernate.jndi.url</tt>, 和<tt class=literal>hibernate.jndi.class</tt>的值来实例化初始环境(initial context). 如果它们没有被指定, 将使用默认的<tt class=literal>InitialContext</tt>. </p>
<p>在你调用<tt class=literal>cfg.buildSessionFactory()</tt>后, Hibernate会自动将<tt class=literal>SessionFactory</tt>注册到JNDI. 这意味这你至少需要在你应用程序的启动代码(或工具类)中完成这个调用, 除非你使用<tt class=literal>HibernateService</tt>来做JMX部署 (见后面讨论). </p>
<p>如果你使用与JNDI绑定的<tt class=literal>SessionFactory</tt>, EJB或任何其他类可以通过一个JNDI查询来获得这个<tt class=literal>SessionFactory</tt>. 请注意, 如果你使用第一章中介绍的帮助类<tt class=literal>HibernateUtil</tt> - 类似Singleton(单实例)注册表, 那么这里的启动代码不是必要的. 但<tt class=literal>HibernateUtil</tt>更多被使用在非托管环境中. </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=configuration-j2ee-currentsession></a>4.8.3.&nbsp; JTA和Session的自动绑定 </h3>
</div>
</div>
<div></div>
</div>
<p>在非托管环境中，我们建议：<tt class=literal>HibernateUtil</tt>和静态<tt class=literal>SessionFactory</tt>一起工作， 由<tt class=literal>ThreadLocal</tt>管理Hibernate <tt class=literal>Session</tt>。 由于一些EJB可能会运行在同一个事务但不同线程的环境中, 所以这个方法不能照搬到EJB环境中. 我们建议在托管环境中，将<tt class=literal>SessionFactory</tt>绑定到JNDI上. </p>
<p>请使用<tt class=literal>SessionFactory</tt>的<tt class=literal>getCurrentSession()</tt>方法来代替 直接使用<tt class=literal>ThreadLocal</tt>去获得Hibernate <tt class=literal>Session</tt>. 如果在当前JTA事务中没有Hibernate <tt class=literal>Session</tt>, 将会启动一个并将它关联到事务中. 对于使用<tt class=literal>getCurrentSession()</tt>获得的每个<tt class=literal>Session</tt>而言， <tt class=literal>hibernate.transaction.flush_before_completion</tt> 和<tt class=literal>hibernate.transaction.auto_close_session</tt>这两个配置选项会自动设置, 因此在容器结束JTA事务时，这些<tt class=literal>Session</tt>会被自动清洗(flush)并关闭. </p>
<p>例如，如果你使用DAO模式来编写你的持久层, 那么在需要时，所有DAO将查找<tt class=literal>SessionFactory</tt>并打开"当前"Session. 没有必要在控制代码和DAO代码间传递<tt class=literal>SessionFactory</tt>或<tt class=literal>Session</tt>的实例. </p>
</div>
<div class=sect2 lang=zh-cn>
<div class=titlepage>
<div>
<div>
<h3 class=title><a name=configuration-j2ee-jmx></a>4.8.4.&nbsp; JMX部署 </h3>
</div>
</div>
<div></div>
</div>
<p>为了将<tt class=literal>SessionFactory</tt>注册到JNDI中<tt class=literal>cfg.buildSessionFactory()</tt>这行代码仍需在某处被执行. 你可在一个<tt class=literal>static</tt>初始化块(像<tt class=literal>HibernateUtil</tt>中的那样)中执行它或将Hibernate部署为一个<span class=emphasis><em>托管的服务</em></span>. </p>
<p>为了部署在一个支持JMX的应用程序服务器上，Hibernate和 <tt class=literal>org.hibernate.jmx.HibernateService</tt>一同分发，如Jboss AS。 实际的部署和配置是由应用程序服务器提供者指定的. 这里是JBoss 4.0.x的<tt class=literal>jboss-service.xml</tt>样例: </p>
<pre class=programlisting>&lt;?xml version="1.0"?&gt;
&lt;server&gt;
&lt;mbean code="org.hibernate.jmx.HibernateService"
name="jboss.jca:service=HibernateFactory,name=HibernateFactory"&gt;
&lt;!-- 必须的服务 --&gt;
&lt;depends&gt;jboss.jca:service=RARDeployer&lt;/depends&gt;
&lt;depends&gt;jboss.jca:service=LocalTxCM,name=HsqlDS&lt;/depends&gt;
&lt;!-- 将Hibernate服务绑定到JNDI --&gt;
&lt;attribute name="JndiName"&gt;java:/hibernate/SessionFactory&lt;/attribute&gt;
&lt;!-- 数据源设置 --&gt;
&lt;attribute name="Datasource"&gt;java:HsqlDS&lt;/attribute&gt;
&lt;attribute name="Dialect"&gt;org.hibernate.dialect.HSQLDialect&lt;/attribute&gt;
&lt;!-- 事务集成 --&gt;
&lt;attribute name="TransactionStrategy"&gt;
org.hibernate.transaction.JTATransactionFactory&lt;/attribute&gt;
&lt;attribute name="TransactionManagerLookupStrategy"&gt;
org.hibernate.transaction.JBossTransactionManagerLookup&lt;/attribute&gt;
&lt;attribute name="FlushBeforeCompletionEnabled"&gt;true&lt;/attribute&gt;
&lt;attribute name="AutoCloseSessionEnabled"&gt;true&lt;/attribute&gt;
&lt;!-- 抓取选项 --&gt;
&lt;attribute name="MaximumFetchDepth"&gt;5&lt;/attribute&gt;
&lt;!-- 二级缓存 --&gt;
&lt;attribute name="SecondLevelCacheEnabled"&gt;true&lt;/attribute&gt;
&lt;attribute name="CacheProviderClass"&gt;org.hibernate.cache.EhCacheProvider&lt;/attribute&gt;
&lt;attribute name="QueryCacheEnabled"&gt;true&lt;/attribute&gt;
&lt;!-- 日志 --&gt;
&lt;attribute name="ShowSqlEnabled"&gt;true&lt;/attribute&gt;
&lt;!-- 映射定义文件 --&gt;
&lt;attribute name="MapResources"&gt;auction/Item.hbm.xml,auction/Category.hbm.xml&lt;/attribute&gt;
&lt;/mbean&gt;
&lt;/server&gt;</pre>
<p>这个文件是部署在<tt class=literal>META-INF</tt>目录下的, 并会被打包到以<tt class=literal>.sar</tt> (service archive)为扩展名的JAR文件中. 同时，你需要打包Hibernate, 它所需要的第三方库, 你编译好的持久化类及你的映射定义文件打包进同一个文档. 你的企业Bean(一般为会话Bean)可能会被打包成它们自己的JAR文件, 但你也许会将EJB JAR文件一同包含进能独立(热)部署的主服务文档. 咨询JBoss AS文档以了解更多的JMX服务与EJB部署的信息.</p>
</div>
</div>
<img src ="http://www.blogjava.net/19851985lili/aggbug/108128.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-04-03 09:52 <a href="http://www.blogjava.net/19851985lili/articles/108128.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>HIBERNATE 常用的语句</title><link>http://www.blogjava.net/19851985lili/articles/108098.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 03 Apr 2007 00:28:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/108098.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/108098.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/108098.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/108098.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/108098.html</trackback:ping><description><![CDATA[<p align=left>&nbsp; </p>
<p align=left><strong><span>Session</span></strong></p>
<p align=left><em><span>Session lifecycle</span></em></p>
<p align=left><span>beginTransaction()</span></p>
<p align=left><span>close()</span></p>
<p align=left><span>isOpen()</span></p>
<p align=left><span>disconnect()</span></p>
<p align=left><span>reconnect()</span></p>
<p align=left><span>reconnect(Connection)</span></p>
<p align=left><span>isConnected()</span></p>
<p align=left><span>flush()</span></p>
<p align=left><span>setFlushMode(FlushMode)</span></p>
<p align=left><span>getFlushMode()</span></p>
<p align=left><em><span>Persistent instances</span></em></p>
<p align=left><span>save(Object)</span></p>
<p align=left><span>save(Object, Serializable)</span></p>
<p align=left><span>saveOrUpdate(Object)</span></p>
<p align=left><span>update(Object)</span></p>
<p align=left><span>update(Object, Serializable)</span></p>
<p align=left><span>lock(Object, LockMode)</span></p>
<p align=left><span>load(Class, Serializable)</span></p>
<p align=left><span>load(Class, Serializable, LockMode)</span></p>
<p align=left><span>load(Object, Serializable)</span></p>
<p align=left><span>refresh(Object)</span></p>
<p align=left><span>refresh(Object, LockMode)</span></p>
<p align=left><span>evict(Object)</span></p>
<p align=left><span>contains(Object)</span></p>
<p align=left><span>delete(Object)</span></p>
<p align=left><span>getIdentifier(Object)</span></p>
<p align=left><span>getCurrentLockMode(Object)</span></p>
<p align=left><em><span>Query factory</span></em></p>
<p align=left><span>createQuery(String)</span></p>
<p align=left><span>createFilter(Object, String)</span></p>
<p align=left><span>createCriteria(Class)</span></p>
<p align=left><span>getNamedQuery(String)</span></p>
<p align=left><em><span>Query execution</span></em></p>
<p align=left><span>find(String)</span></p>
<p align=left><span>find(String, Object, Type)</span></p>
<p align=left><span>find(String, Object[], Type[])</span></p>
<p align=left><span>iterate(String)</span></p>
<p align=left><span>iterate(String, Object, Type)</span></p>
<p align=left><span>iterate(String, Object[], Type[])</span></p>
<p align=left><span>filter(Object, String)</span></p>
<p align=left><span>filter(Object, String, Object, Type)</span></p>
<p align=left><span>filter(String, Object[], Type[])</span></p>
<p align=left><span>delete(String)</span></p>
<p align=left><span>delete(String, Object, Type)</span></p>
<p align=left><span>delete(String, Object[], Type[])</span></p>
<p align=left><strong><span>Validatable</span></strong></p>
<p align=left><em><span>Instance state validation</span></em></p>
<p align=left><span>validate()</span></p>
<p align=left><strong><span>Hibernate</span></strong></p>
<p align=left><em><span>Proxies</span></em></p>
<p align=left><span>initialize(Object)</span></p>
<p align=left><span>isInitialized(Object)</span></p>
<p align=left><span>getClass(Object)</span></p>
<p align=left><em><span>Blob/Clob factory</span></em></p>
<p align=left><span>createBlob(InputStream, int)</span></p>
<p align=left><span>createBlob(byte[])</span></p>
<p align=left><span>createClob(Reader, int)</span></p>
<p align=left><span>createClob(String)</span></p>
<p align=left><em><span>Type factory</span></em></p>
<p align=left><span>entity(Class)</span></p>
<p align=left><span>enum(Class)</span></p>
<p align=left><span>custom(Class)</span></p>
<p align=left><span>any(Type, Type)</span></p>
<p align=left><span>serializable(Class)</span></p>
<p align=left><span>BIG_DECIMAL</span></p>
<p align=left><span>BINARY</span></p>
<p align=left><span>BLOB</span></p>
<p align=left><span>BOOLEAN</span></p>
<p align=left><span>BYTE</span></p>
<p align=left><span>CALENDAR</span></p>
<p align=left><span>CALENDAR_DATE</span></p>
<p align=left><span>CHARACTER</span></p>
<p align=left><span>CLASS</span></p>
<p align=left><span>CLOB</span></p>
<p align=left><span>CURRENCY</span></p>
<p align=left><span>DATE</span></p>
<p align=left><span>DOUBLE</span></p>
<p align=left><span>FLOAT</span></p>
<p align=left><span>INTEGER</span></p>
<p align=left><span>LOCALE</span></p>
<p align=left><span>LONG</span></p>
<p align=left><span>OBJECT</span></p>
<p align=left><span>SERIALIZABLE</span></p>
<p align=left><span>SHORT</span></p>
<p align=left><span>STRING</span></p>
<p align=left><span>TIME</span></p>
<p align=left><span>TIMESTAMP</span></p>
<p align=left><span>TIMEZONE</span></p>
<p align=left><span>TRUE_FALSE</span></p>
<p align=left><span>YES_NO</span></p>
<p align=left><strong><span>Transaction</span></strong></p>
<p align=left><em><span>Lifecycle</span></em></p>
<p align=left><span>commit()</span></p>
<p align=left><span>rollback()</span></p>
<p align=left><span>wasCommitted()</span></p>
<p align=left><span>wasRolledBack()</span></p>
<p align=left><strong><span>Lifecycle</span></strong></p>
<p align=left><em><span>Persistent instance lifecycle</span></em></p>
<p align=left><span>onSave(Session)</span></p>
<p align=left><span>onUpdate(Session)</span></p>
<p align=left><span>onDelete(Session)</span></p>
<p align=left><span>onLoad(Session, Serializable)</span></p>
<p align=left><span>VETO</span></p>
<p align=left><span>NO_VETO</span></p>
<p align=left><strong><span>SessionFactory</span></strong></p>
<p align=left><em><span>SessionFactory lifecycle</span></em></p>
<p align=left><span>close()</span></p>
<p align=left><em><span>Session factory</span></em></p>
<p align=left><span>openSession()</span></p>
<p align=left><span>openSession(Interceptor)</span></p>
<p align=left><span>openSession(Connection)</span></p>
<p align=left><span>openSession(Connection, Interceptor)</span></p>
<p align=left><em><span>Cache management</span></em></p>
<p align=left><span>evict(Class)</span></p>
<p align=left><span>evict(Class, Serializable)</span></p>
<p align=left><span>evictCollection(String)</span></p>
<p align=left><span>evictCollection(String, Serializable)</span></p>
<p align=left><em><span>Metadata factory</span></em></p>
<p align=left><span>getClassMetadata(Class)</span></p>
<p align=left><span>getCollectionMetadata(String)</span></p>
<p align=left><span>getAllClassMetadata()</span></p>
<p align=left><span>getAllCollectionMetadata()</span></p>
<p align=left><strong><span>Query</span></strong></p>
<p align=left><em><span>Metadata</span></em></p>
<p align=left><span>getQueryString()</span></p>
<p align=left><span>getReturnTypes()</span></p>
<p align=left><span>getNamedParameters()</span></p>
<p align=left><em><span>Query execution</span></em></p>
<p align=left><span>list()</span></p>
<p align=left><span>iterate()</span></p>
<p align=left><span>scroll()</span></p>
<p align=left><span>setMaxResults(int)</span></p>
<p align=left><span>setFirstResult(int)</span></p>
<p align=left><span>setLockMode(String, LockMode)</span></p>
<p align=left><span>setTimeout(int)</span></p>
<p align=left><em><span>Parameter binding</span></em></p>
<p align=left><span>setProperties(Object)</span></p>
<p align=left><span>setParameterList(String, Collection)</span></p>
<p align=left><span>setParameterList(String, Collection, Type)</span></p>
<p align=left><span>setParameterList(String, Object[])</span></p>
<p align=left><span>setParameterList(String, Object[], Type)</span></p>
<p align=left><span>setParameter(String, Object)</span></p>
<p align=left><span>setParameter(String, Object, Type)</span></p>
<p align=left><span>setParameter(int, Object)</span></p>
<p align=left><span>setParameter(int, Object, Type)</span></p>
<p align=left><em><span>setString(String, String)</span></em></p>
<p align=left><em><span>setString(int, String)</span></em></p>
<p align=left><span>...</span></p>
<p align=left>&nbsp;</p>
<img src ="http://www.blogjava.net/19851985lili/aggbug/108098.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-04-03 08:28 <a href="http://www.blogjava.net/19851985lili/articles/108098.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>研究一下springside的核心部分源代码 </title><link>http://www.blogjava.net/19851985lili/articles/98475.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Wed, 07 Feb 2007 00:45:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/98475.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/98475.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/98475.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/98475.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/98475.html</trackback:ping><description><![CDATA[说明:这里的代码是我参考了springside的源代码后作了一些比较小的改动,这里没有给出完整的例子,只是讨论一下核心的代码)<br />这里想说的代码主要是泛型DAO层的应用与分页的写法.<br /><br />分页,采用了hibernate的一些API来分页,这里同时采用了两种分页方式,CriteriaPage分页方式,适用于多表单时查询后分页用的,而第二种方式是采用Hql语句查询后分页的.代码如下:<br /><br />CriteriaPage.java文件:
<div class="dp-highlighter"><div class="bar"></div><ol class="dp-j"><li class="alt"><span><span class="keyword">package</span><span> org.mmc.commons;   </span></span></li><li class=""><span>  </span></li><li class="alt"><span></span><span class="keyword">import</span><span> java.util.ArrayList;   </span></li><li class=""><span></span><span class="keyword">import</span><span> java.util.List;   </span></li><li class="alt"><span>  </span></li><li class=""><span></span><span class="keyword">import</span><span> org.hibernate.Criteria;   </span></li><li class="alt"><span></span><span class="keyword">import</span><span> org.hibernate.criterion.CriteriaSpecification;   </span></li><li class=""><span></span><span class="keyword">import</span><span> org.hibernate.criterion.Projection;   </span></li><li class="alt"><span></span><span class="keyword">import</span><span> org.hibernate.criterion.Projections;   </span></li><li class=""><span></span><span class="keyword">import</span><span> org.hibernate.impl.CriteriaImpl;   </span></li><li class="alt"><span></span><span class="keyword">import</span><span> org.hibernate.impl.CriteriaImpl.OrderEntry;   </span></li><li class=""><span></span><span class="keyword">import</span><span> org.mmc.utils.BeanUtils;   </span></li><li class="alt"><span>  </span></li><li class=""><span></span><span class="comment">/** </span>  
</li><li class="alt"><span><span class="comment"> * 使用Hql查询的的分页查询类. </span> </span></li><li class=""><span><span class="comment"> * 支持执行Count查询取得总记录条数 </span> </span></li><li class="alt"><span><span class="comment"> * 本类参考了springside项目的分页设计 </span> </span></li><li class=""><span><span class="comment"> */</span><span>  </span></span></li><li class="alt"><span></span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> CriteriaPage {   </span></li><li class=""><span>  </span></li><li class="alt"><span>    </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">     * 得到一个PageInstance实例,. </span> </span></li><li class="alt"><span><span class="comment">     */</span><span>  </span></span></li><li class=""><span>    </span><span class="keyword">public</span><span> </span><span class="keyword">static</span><span> Page getPageInstance(Criteria criteria, </span><span class="keyword">int</span><span> pageNo, </span><span class="keyword">int</span><span> pageSize) {   </span></li><li class="alt"><span>          </span></li><li class=""><span>            </span><span class="keyword">return</span><span> CriteriaPage.getPageInstanceByCount(criteria, pageNo, pageSize);   </span></li><li class="alt"><span>    }   </span></li><li class=""><span>  </span></li><li class="alt"><span>    </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">     * 以查询Count的形式获取totalCount的函数 </span> </span></li><li class="alt"><span><span class="comment">     */</span><span>  </span></span></li><li class=""><span>    </span><span class="keyword">protected</span><span> </span><span class="keyword">static</span><span> Page getPageInstanceByCount(Criteria criteria, </span><span class="keyword">int</span><span> pageNo, </span><span class="keyword">int</span><span> pageSize) {   </span></li><li class="alt"><span>        CriteriaImpl impl = (CriteriaImpl) criteria;   </span></li><li class=""><span>  </span></li><li class="alt"><span>        </span><span class="comment">//先把Projection和OrderBy条件取出来,清空两者来执行Count操作 </span><span>  </span></li><li class=""><span>        Projection projection = impl.getProjection();   </span></li><li class="alt"><span>        List orderEntries;   </span></li><li class=""><span>        </span><span class="keyword">try</span><span> {   </span></li><li class="alt"><span>            orderEntries = (List) BeanUtils.getPrivateProperty(impl, </span><span class="string">"orderEntries"</span><span>);   </span></li><li class=""><span>            BeanUtils.setPrivateProperty(impl, </span><span class="string">"orderEntries"</span><span>, </span><span class="keyword">new</span><span> ArrayList());   </span></li><li class="alt"><span>        }   </span></li><li class=""><span>        </span><span class="keyword">catch</span><span> (Exception e) {   </span></li><li class="alt"><span>            </span><span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> InternalError(</span><span class="string">" Runtime Exception impossibility throw "</span><span>);   </span></li><li class=""><span>        }   </span></li><li class="alt"><span>  </span></li><li class=""><span>        </span><span class="comment">//执行查询 </span><span>  </span></li><li class="alt"><span>        </span><span class="keyword">int</span><span> totalCount = (Integer) criteria.setProjection(Projections.rowCount()).uniqueResult();   </span></li><li class=""><span>  </span></li><li class="alt"><span>        </span><span class="comment">//将之前的Projection和OrderBy条件重新设回去 </span><span>  </span></li><li class=""><span>        criteria.setProjection(projection);   </span></li><li class="alt"><span>        </span><span class="keyword">if</span><span> (projection == </span><span class="keyword">null</span><span>) {   </span></li><li class=""><span>            criteria.setResultTransformer(CriteriaSpecification.ROOT_ENTITY);   </span></li><li class="alt"><span>        }   </span></li><li class=""><span>  </span></li><li class="alt"><span>        </span><span class="keyword">try</span><span> {   </span></li><li class=""><span>            BeanUtils.setPrivateProperty(impl, </span><span class="string">"orderEntries"</span><span>, orderEntries);   </span></li><li class="alt"><span>        } </span><span class="keyword">catch</span><span> (Exception e) {   </span></li><li class=""><span>            </span><span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> InternalError(</span><span class="string">" Runtime Exception impossibility throw "</span><span>);   </span></li><li class="alt"><span>        }   </span></li><li class=""><span>  </span></li><li class="alt"><span>        </span><span class="keyword">return</span><span> getPageResult(criteria, totalCount, pageNo, pageSize);   </span></li><li class=""><span>    }   </span></li><li class="alt"><span>       </span></li><li class=""><span>    </span><span class="comment">/** </span>  
</li><li class="alt"><span><span class="comment">     * 取得totalCount后，根据pageNo和PageSize, 执行criteria的分页查询，取得Page变量 </span> </span></li><li class=""><span><span class="comment">     */</span><span>  </span></span></li><li class="alt"><span>    </span><span class="keyword">private</span><span> </span><span class="keyword">static</span><span> Page getPageResult(Criteria criteria, </span><span class="keyword">int</span><span> totalCount, </span><span class="keyword">int</span><span> pageNo, </span><span class="keyword">int</span><span> pageSize) {   </span></li><li class=""><span>        </span><span class="keyword">if</span><span> (totalCount &lt; </span><span class="number">1</span><span>) </span><span class="keyword">return</span><span> </span><span class="keyword">new</span><span> Page();   </span></li><li class="alt"><span>  </span></li><li class=""><span>        </span><span class="keyword">int</span><span> startIndex = Page.getStartOfPage(pageNo, pageSize);   </span></li><li class="alt"><span>        List list = criteria.setFirstResult(startIndex).setMaxResults(pageSize).list();   </span></li><li class=""><span>  </span></li><li class="alt"><span>        </span><span class="keyword">return</span><span> </span><span class="keyword">new</span><span> Page(startIndex, totalCount, pageSize, list);   </span></li><li class=""><span>    }   </span></li><li class="alt"><span>  </span></li><li class=""><span>}   </span></li><li class="alt"><span>  </span></li></ol></div><p><br /><font size="4">HqlPage.java文件的代码</font><font size="4"></font></p><pre><br />Page.java文件的源代码如下:</pre><font size="4"><div class="dp-highlighter"><div class="bar"></div><ol class="dp-j"><li class="alt"><span><span class="keyword">package</span><span> org.mmc.commons;   </span></span></li><li class=""><span>  </span></li><li class="alt"><span></span><span class="keyword">import</span><span> java.util.ArrayList;   </span></li><li class=""><span>  </span></li><li class="alt"><span></span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment"> * 分页对象. 包含数据及分页信息. </span> </span></li><li class="alt"><span><span class="comment"> *  </span> </span></li><li class=""><span><span class="comment"> * @author lighter 天马行空 </span> </span></li><li class="alt"><span><span class="comment"> */</span><span>  </span></span></li><li class=""><span></span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> Page </span><span class="keyword">implements</span><span> java.io.Serializable {   </span></li><li class="alt"><span> </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">  * 当前页第一条数据的位置,从0开始 </span> </span></li><li class="alt"><span><span class="comment">  */</span><span>  </span></span></li><li class=""><span> </span><span class="keyword">private</span><span> </span><span class="keyword">int</span><span> start;   </span></li><li class="alt"><span>  </span></li><li class=""><span> </span><span class="comment">/** </span>  
</li><li class="alt"><span><span class="comment">  * 每页的记录数 </span> </span></li><li class=""><span><span class="comment">  */</span><span>  </span></span></li><li class="alt"><span> </span><span class="keyword">private</span><span> </span><span class="keyword">int</span><span> pageSize = Constants.DEFAULT_PAGE_SIZE;   </span></li><li class=""><span>  </span></li><li class="alt"><span> </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">  * 当前页中存放的记录 </span> </span></li><li class="alt"><span><span class="comment">  */</span><span>  </span></span></li><li class=""><span> </span><span class="keyword">private</span><span> Object data;   </span></li><li class="alt"><span>  </span></li><li class=""><span> </span><span class="comment">/** </span>  
</li><li class="alt"><span><span class="comment">  * 总记录数 </span> </span></li><li class=""><span><span class="comment">  */</span><span>  </span></span></li><li class="alt"><span> </span><span class="keyword">private</span><span> </span><span class="keyword">int</span><span> totalCount;   </span></li><li class=""><span>  </span></li><li class="alt"><span> </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">  * 构造方法，只构造空页 </span> </span></li><li class="alt"><span><span class="comment">  */</span><span>  </span></span></li><li class=""><span> </span><span class="keyword">public</span><span> Page() {   </span></li><li class="alt"><span>  </span><span class="keyword">this</span><span>(</span><span class="number">0</span><span>, </span><span class="number">0</span><span>, Constants.DEFAULT_PAGE_SIZE, </span><span class="keyword">new</span><span> ArrayList());   </span></li><li class=""><span> }   </span></li><li class="alt"><span>  </span></li><li class=""><span> </span><span class="comment">/** </span>  
</li><li class="alt"><span><span class="comment">  * 默认构造方法 </span> </span></li><li class=""><span><span class="comment">  *  </span> </span></li><li class="alt"><span><span class="comment">  * @param start </span> </span></li><li class=""><span><span class="comment">  *            本页数据在数据库中的起始位置 </span> </span></li><li class="alt"><span><span class="comment">  * @param totalSize </span> </span></li><li class=""><span><span class="comment">  *            数据库中总记录条数 </span> </span></li><li class="alt"><span><span class="comment">  * @param pageSize </span> </span></li><li class=""><span><span class="comment">  *            本页容量 </span> </span></li><li class="alt"><span><span class="comment">  * @param data </span> </span></li><li class=""><span><span class="comment">  *            本页包含的数据 </span> </span></li><li class="alt"><span><span class="comment">  */</span><span>  </span></span></li><li class=""><span> </span><span class="keyword">public</span><span> Page(</span><span class="keyword">int</span><span> start, </span><span class="keyword">int</span><span> totalSize, </span><span class="keyword">int</span><span> pageSize, Object data) {   </span></li><li class="alt"><span>  </span><span class="keyword">this</span><span>.pageSize = pageSize;   </span></li><li class=""><span>  </span><span class="keyword">this</span><span>.start = start;   </span></li><li class="alt"><span>  </span><span class="keyword">this</span><span>.totalCount = totalSize;   </span></li><li class=""><span>  </span><span class="keyword">this</span><span>.data = data;   </span></li><li class="alt"><span> }   </span></li><li class=""><span>  </span></li><li class="alt"><span> </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">  * 取数据库中包含的总记录数 </span> </span></li><li class="alt"><span><span class="comment">  */</span><span>  </span></span></li><li class=""><span> </span><span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getTotalCount() {   </span></li><li class="alt"><span>  </span><span class="keyword">return</span><span> </span><span class="keyword">this</span><span>.totalCount;   </span></li><li class=""><span> }   </span></li><li class="alt"><span>  </span></li><li class=""><span> </span><span class="comment">/** </span>  
</li><li class="alt"><span><span class="comment">  * 取总页数 </span> </span></li><li class=""><span><span class="comment">  */</span><span>  </span></span></li><li class="alt"><span> </span><span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getTotalPageCount() {   </span></li><li class=""><span>  </span><span class="keyword">if</span><span> (totalCount % pageSize == </span><span class="number">0</span><span>)   </span></li><li class="alt"><span>   </span><span class="keyword">return</span><span> totalCount / pageSize;   </span></li><li class=""><span>  </span><span class="keyword">else</span><span>  </span></li><li class="alt"><span>   </span><span class="keyword">return</span><span> totalCount / pageSize + </span><span class="number">1</span><span>;   </span></li><li class=""><span> }   </span></li><li class="alt"><span>  </span></li><li class=""><span> </span><span class="comment">/** </span>  
</li><li class="alt"><span><span class="comment">  * 取每页数据容量 </span> </span></li><li class=""><span><span class="comment">  */</span><span>  </span></span></li><li class="alt"><span> </span><span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getPageSize() {   </span></li><li class=""><span>  </span><span class="keyword">return</span><span> pageSize;   </span></li><li class="alt"><span> }   </span></li><li class=""><span>  </span></li><li class="alt"><span> </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">  * 当前页中的记录 </span> </span></li><li class="alt"><span><span class="comment">  */</span><span>  </span></span></li><li class=""><span> </span><span class="keyword">public</span><span> Object getResult() {   </span></li><li class="alt"><span>  </span><span class="keyword">return</span><span> data;   </span></li><li class=""><span> }   </span></li><li class="alt"><span>  </span></li><li class=""><span> </span><span class="comment">/** </span>  
</li><li class="alt"><span><span class="comment">  * 取当前页码,页码从1开始 </span> </span></li><li class=""><span><span class="comment">  */</span><span>  </span></span></li><li class="alt"><span> </span><span class="keyword">public</span><span> </span><span class="keyword">int</span><span> getCurrentPageNo() {   </span></li><li class=""><span>  </span><span class="keyword">return</span><span> (start / pageSize) + </span><span class="number">1</span><span>;   </span></li><li class="alt"><span> }   </span></li><li class=""><span>  </span></li><li class="alt"><span> </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">  * 是否有下一页 </span> </span></li><li class="alt"><span><span class="comment">  */</span><span>  </span></span></li><li class=""><span> </span><span class="keyword">public</span><span> </span><span class="keyword">boolean</span><span> hasNextPage() {   </span></li><li class="alt"><span>  </span><span class="keyword">return</span><span> (</span><span class="keyword">this</span><span>.getCurrentPageNo() &lt; </span><span class="keyword">this</span><span>.getTotalPageCount() - </span><span class="number">1</span><span>);   </span></li><li class=""><span> }   </span></li><li class="alt"><span>  </span></li><li class=""><span> </span><span class="comment">/** </span>  
</li><li class="alt"><span><span class="comment">  * 是否有上一页 </span> </span></li><li class=""><span><span class="comment">  */</span><span>  </span></span></li><li class="alt"><span> </span><span class="keyword">public</span><span> </span><span class="keyword">boolean</span><span> hasPreviousPage() {   </span></li><li class=""><span>  </span><span class="keyword">return</span><span> (</span><span class="keyword">this</span><span>.getCurrentPageNo() &gt; </span><span class="number">1</span><span>);   </span></li><li class="alt"><span> }   </span></li><li class=""><span>  </span></li><li class="alt"><span> </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">  * 获取任一页第一条数据的位置，每页条数使用默认值 </span> </span></li><li class="alt"><span><span class="comment">  * 关键字设为pretected </span> </span></li><li class=""><span><span class="comment">  */</span><span>  </span></span></li><li class="alt"><span> </span><span class="keyword">protected</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">int</span><span> getStartOfPage(</span><span class="keyword">int</span><span> pageNo) {   </span></li><li class=""><span>  </span><span class="keyword">return</span><span> getStartOfPage(pageNo, Constants.DEFAULT_PAGE_SIZE);   </span></li><li class="alt"><span> }   </span></li><li class=""><span>  </span></li><li class="alt"><span> </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">  * 获取任一页第一条数据的位置,startIndex从0开始 </span> </span></li><li class="alt"><span><span class="comment">  * 关键字设为pretected </span> </span></li><li class=""><span><span class="comment">  */</span><span>  </span></span></li><li class="alt"><span> </span><span class="keyword">protected</span><span> </span><span class="keyword">static</span><span> </span><span class="keyword">int</span><span> getStartOfPage(</span><span class="keyword">int</span><span> pageNo, </span><span class="keyword">int</span><span> pageSize) {   </span></li><li class=""><span>  </span><span class="keyword">return</span><span> (pageNo - </span><span class="number">1</span><span>) * pageSize;   </span></li><li class="alt"><span> }   </span></li><li class=""><span>}   </span></li><li class="alt"><span>  </span></li></ol></div></font><pre><br /><br />分页的改造已经完成,现在重构一下DAO层的写法,利用了spring对hibernate支持的一些的API.<br /></pre><pre>DAO层:<br />AbstractHibernateDao.java的源代码</pre><font size="4"><div class="dp-highlighter"><div class="bar"></div><ol class="dp-j"><li class="alt"><span><span class="keyword">package</span><span> org.mmc.dao;   </span></span></li><li class=""><span>  </span></li><li class="alt"><span></span><span class="keyword">import</span><span> org.apache.commons.beanutils.PropertyUtils;   </span></li><li class=""><span></span><span class="keyword">import</span><span> org.apache.commons.lang.StringUtils;   </span></li><li class="alt"><span></span><span class="keyword">import</span><span> org.apache.commons.logging.Log;   </span></li><li class=""><span></span><span class="keyword">import</span><span> org.apache.commons.logging.LogFactory;   </span></li><li class="alt"><span></span><span class="keyword">import</span><span> org.hibernate.Criteria;   </span></li><li class=""><span></span><span class="keyword">import</span><span> org.hibernate.criterion.MatchMode;   </span></li><li class="alt"><span></span><span class="keyword">import</span><span> org.hibernate.criterion.Order;   </span></li><li class=""><span></span><span class="keyword">import</span><span> org.hibernate.criterion.Projections;   </span></li><li class="alt"><span></span><span class="keyword">import</span><span> org.hibernate.criterion.Restrictions;   </span></li><li class=""><span></span><span class="keyword">import</span><span> org.springframework.orm.ObjectRetrievalFailureException;   </span></li><li class="alt"><span></span><span class="keyword">import</span><span> org.springframework.orm.hibernate3.support.HibernateDaoSupport;   </span></li><li class=""><span></span><span class="keyword">import</span><span> org.springframework.util.Assert;   </span></li><li class="alt"><span></span><span class="keyword">import</span><span> org.springframework.util.CollectionUtils;   </span></li><li class=""><span></span><span class="keyword">import</span><span> org.mmc.utils.GenericsUtils;   </span></li><li class="alt"><span>  </span></li><li class=""><span></span><span class="keyword">import</span><span> java.io.Serializable;   </span></li><li class="alt"><span></span><span class="keyword">import</span><span> java.util.List;   </span></li><li class=""><span></span><span class="keyword">import</span><span> java.util.Map;   </span></li><li class="alt"><span></span><span class="keyword">import</span><span> java.util.Set;   </span></li><li class=""><span>  </span></li><li class="alt"><span></span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment"> * 纯Hibernate Entity DAO基类. </span> </span></li><li class="alt"><span><span class="comment"> * 通过泛型，子类无需扩展任何函数即拥有完整的CRUD操作. </span> </span></li><li class=""><span><span class="comment"> * </span> </span></li><li class="alt"><span><span class="comment"> */</span><span>  </span></span></li><li class=""><span></span><span class="keyword">abstract</span><span> </span><span class="keyword">public</span><span> </span><span class="keyword">class</span><span> AbstractHibernateDao </span><span class="keyword">extends</span><span> HibernateDaoSupport {   </span></li><li class="alt"><span>  </span></li><li class=""><span>    </span><span class="keyword">protected</span><span> Log logger = LogFactory.getLog(getClass());   </span></li><li class="alt"><span>  </span></li><li class=""><span>    </span><span class="comment">/** </span>  
</li><li class="alt"><span><span class="comment">     * Dao所管理的Entity类型. </span> </span></li><li class=""><span><span class="comment">     */</span><span>  </span></span></li><li class="alt"><span>    </span><span class="keyword">protected</span><span> Class entityClass;   </span></li><li class=""><span>  </span></li><li class="alt"><span>    </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">     * 取得entityClass的函数. </span> </span></li><li class="alt"><span><span class="comment">     * JDK1.4不支持泛型的子类可以抛开Class entityClass,重新实现此函数达到相同效果。 </span> </span></li><li class=""><span><span class="comment">     */</span><span>  </span></span></li><li class="alt"><span>    </span><span class="keyword">protected</span><span> Class getEntityClass() {   </span></li><li class=""><span>        </span><span class="keyword">return</span><span> entityClass;   </span></li><li class="alt"><span>    }   </span></li><li class=""><span>  </span></li><li class="alt"><span>    </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">     * 在构造函数中将泛型T.class赋给entityClass </span> </span></li><li class="alt"><span><span class="comment">     */</span><span>  </span></span></li><li class=""><span>    </span><span class="keyword">public</span><span> AbstractHibernateDao() {   </span></li><li class="alt"><span>        entityClass = GenericsUtils.getGenericClass(getClass());   </span></li><li class=""><span>    }   </span></li><li class="alt"><span>  </span></li><li class=""><span>    </span><span class="keyword">public</span><span> T get(Serializable id) {   </span></li><li class="alt"><span>        T o = (T) getHibernateTemplate().get(getEntityClass(), id);   </span></li><li class=""><span>        </span><span class="keyword">if</span><span> (o == </span><span class="keyword">null</span><span>)   </span></li><li class="alt"><span>            </span><span class="keyword">throw</span><span> </span><span class="keyword">new</span><span> ObjectRetrievalFailureException(getEntityClass(), id);   </span></li><li class=""><span>        </span><span class="keyword">return</span><span> o;   </span></li><li class="alt"><span>    }   </span></li><li class=""><span>  </span></li><li class="alt"><span>    </span><span class="keyword">public</span><span> List getAll() {   </span></li><li class=""><span>        </span><span class="keyword">return</span><span> getHibernateTemplate().loadAll(getEntityClass());   </span></li><li class="alt"><span>    }   </span></li><li class=""><span>  </span></li><li class="alt"><span>    </span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> save(Object o) {   </span></li><li class=""><span>        getHibernateTemplate().saveOrUpdate(o);   </span></li><li class="alt"><span>    }   </span></li><li class=""><span>  </span></li><li class="alt"><span>    </span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> removeById(Serializable id) {   </span></li><li class=""><span>        remove(get(id));   </span></li><li class="alt"><span>    }   </span></li><li class=""><span>  </span></li><li class="alt"><span>    </span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> remove(Object o) {   </span></li><li class=""><span>        getHibernateTemplate().delete(o);   </span></li><li class="alt"><span>    }   </span></li><li class=""><span>  </span></li><li class="alt"><span>    </span><span class="keyword">public</span><span> List find(String hsql, Object... values) {   </span></li><li class=""><span>        </span><span class="keyword">if</span><span> (values.length == </span><span class="number">0</span><span>)   </span></li><li class="alt"><span>            </span><span class="keyword">return</span><span> getHibernateTemplate().find(hsql);   </span></li><li class=""><span>        </span><span class="keyword">else</span><span>  </span></li><li class="alt"><span>            </span><span class="keyword">return</span><span> getHibernateTemplate().find(hsql, values);   </span></li><li class=""><span>    }   </span></li><li class="alt"><span>  </span></li><li class=""><span>    </span><span class="comment">/** </span>  
</li><li class="alt"><span><span class="comment">     * 根据属性名和属性值查询对象. </span> </span></li><li class=""><span><span class="comment">     * </span> </span></li><li class="alt"><span><span class="comment">     * @return 符合条件的唯一对象 </span> </span></li><li class=""><span><span class="comment">     */</span><span>  </span></span></li><li class="alt"><span>    </span><span class="keyword">public</span><span> T findUniqueBy(String name, Object value) {   </span></li><li class=""><span>        Criteria criteria = getSession().createCriteria(getEntityClass());   </span></li><li class="alt"><span>        criteria.add(Restrictions.eq(name, value));   </span></li><li class=""><span>        </span><span class="keyword">return</span><span> (T) criteria.uniqueResult();   </span></li><li class="alt"><span>    }   </span></li><li class=""><span>  </span></li><li class="alt"><span>    </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">     * 根据属性名和属性值查询对象. </span> </span></li><li class="alt"><span><span class="comment">     * </span> </span></li><li class=""><span><span class="comment">     * @return 符合条件的对象列表 </span> </span></li><li class="alt"><span><span class="comment">     */</span><span>  </span></span></li><li class=""><span>    </span><span class="keyword">public</span><span> List findBy(String name, Object value) {   </span></li><li class="alt"><span>        Assert.hasText(name);   </span></li><li class=""><span>        Criteria criteria = getSession().createCriteria(getEntityClass());   </span></li><li class="alt"><span>        criteria.add(Restrictions.eq(name, value));   </span></li><li class=""><span>        </span><span class="keyword">return</span><span> criteria.list();   </span></li><li class="alt"><span>    }   </span></li><li class=""><span>  </span></li><li class="alt"><span>    </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">     * 根据属性名和属性值以Like AnyWhere方式查询对象. </span> </span></li><li class="alt"><span><span class="comment">     */</span><span>  </span></span></li><li class=""><span>    </span><span class="keyword">public</span><span> List findByLike(String name, String value) {   </span></li><li class="alt"><span>        Assert.hasText(name);   </span></li><li class=""><span>        Criteria criteria = getSession().createCriteria(getEntityClass());   </span></li><li class="alt"><span>        criteria.add(Restrictions.like(name, value, MatchMode.ANYWHERE));   </span></li><li class=""><span>        </span><span class="keyword">return</span><span> criteria.list();   </span></li><li class="alt"><span>    }   </span></li><li class=""><span>  </span></li><li class="alt"><span>    </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">     * 根据Map中过滤条件进行查询. </span> </span></li><li class="alt"><span><span class="comment">     * </span> </span></li><li class=""><span><span class="comment">     * @param filter        过滤条件. </span> </span></li><li class="alt"><span><span class="comment">     * @param criteriaSetup 将Map中条件转换为criteria的call back类 </span> </span></li><li class=""><span><span class="comment">     */</span><span>  </span></span></li><li class="alt"><span>    </span><span class="keyword">public</span><span> List findBy(Map filter, CriteriaSetup criteriaSetup) {   </span></li><li class=""><span>        Criteria criteria = getEntityCriteria();   </span></li><li class="alt"><span>        </span><span class="keyword">if</span><span> (!CollectionUtils.isEmpty(filter)) {   </span></li><li class=""><span>            criteriaSetup.setup(criteria, filter);   </span></li><li class="alt"><span>        }   </span></li><li class=""><span>        </span><span class="keyword">return</span><span> criteria.list();   </span></li><li class="alt"><span>    }   </span></li><li class=""><span>  </span></li><li class="alt"><span>    </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">     * 函数作用同{@link #findBy(Map,CriteriaSetup)} </span> </span></li><li class="alt"><span><span class="comment">     * 如果不需要分页,子类可直接重载此函数. </span> </span></li><li class=""><span><span class="comment">     */</span><span>  </span></span></li><li class="alt"><span>    </span><span class="keyword">public</span><span> List findBy(Map filter) {   </span></li><li class=""><span>        </span><span class="keyword">return</span><span> findBy(filter, getDefaultCriteriaSetup());   </span></li><li class="alt"><span>    }   </span></li><li class=""><span>  </span></li><li class="alt"><span>    </span><span class="keyword">protected</span><span> CriteriaSetup getDefaultCriteriaSetup() {   </span></li><li class=""><span>        </span><span class="keyword">return</span><span> </span><span class="keyword">new</span><span> CriteriaSetup() {   </span></li><li class="alt"><span>            </span><span class="keyword">public</span><span> </span><span class="keyword">void</span><span> setup(Criteria criteria, Map filter) {   </span></li><li class=""><span>                </span><span class="keyword">if</span><span> (filter != </span><span class="keyword">null</span><span> &amp;&amp; !filter.isEmpty()) {   </span></li><li class="alt"><span>                    Set keys = filter.keySet();   </span></li><li class=""><span>                    </span><span class="keyword">for</span><span> (Object key : keys) {   </span></li><li class="alt"><span>                        String value = (String) filter.get(key);   </span></li><li class=""><span>                        </span><span class="keyword">if</span><span> (StringUtils.isNotBlank(value))   </span></li><li class="alt"><span>                            criteria.add(Restrictions.eq((String) key, value));   </span></li><li class=""><span>                    }   </span></li><li class="alt"><span>                }   </span></li><li class=""><span>            }   </span></li><li class="alt"><span>        };   </span></li><li class=""><span>    }   </span></li><li class="alt"><span>  </span></li><li class=""><span>    </span><span class="comment">/** </span>  
</li><li class="alt"><span><span class="comment">     * 取得Entity的Criteria. </span> </span></li><li class=""><span><span class="comment">     */</span><span>  </span></span></li><li class="alt"><span>    </span><span class="keyword">protected</span><span> Criteria getEntityCriteria() {   </span></li><li class=""><span>        </span><span class="keyword">return</span><span> getSession().createCriteria(getEntityClass());   </span></li><li class="alt"><span>    }   </span></li><li class=""><span>  </span></li><li class="alt"><span>    </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">     * 构造Criteria的排序条件默认函数.可供其他查询函数调用 </span> </span></li><li class="alt"><span><span class="comment">     * </span> </span></li><li class=""><span><span class="comment">     * @param criteria Criteria实例. </span> </span></li><li class="alt"><span><span class="comment">     * @param sortMap  排序条件. </span> </span></li><li class=""><span><span class="comment">     * @param entity   entity对象,用于使用反射来获取某些属性信息 </span> </span></li><li class="alt"><span><span class="comment">     */</span><span>  </span></span></li><li class=""><span>    </span><span class="keyword">protected</span><span> </span><span class="keyword">void</span><span> sortCriteria(Criteria criteria, Map sortMap, Object entity) {   </span></li><li class="alt"><span>        </span><span class="keyword">if</span><span> (!sortMap.isEmpty()) {   </span></li><li class=""><span>            </span><span class="keyword">for</span><span> (Object o : sortMap.keySet()) {   </span></li><li class="alt"><span>                String fieldName = o.toString();   </span></li><li class=""><span>                String orderType = sortMap.get(fieldName).toString();   </span></li><li class="alt"><span>  </span></li><li class=""><span>                </span><span class="comment">//处理嵌套属性如category.name,modify_user.id,暂时只处理一级嵌套 </span><span>  </span></li><li class="alt"><span>                </span><span class="keyword">if</span><span> (fieldName.indexOf(</span><span class="string">'.'</span><span>) != -</span><span class="number">1</span><span>) {   </span></li><li class=""><span>                    String alias = StringUtils.substringBefore(fieldName, </span><span class="string">"."</span><span>);   </span></li><li class="alt"><span>                    String aliasType = alias;   </span></li><li class=""><span>                    </span><span class="keyword">try</span><span> {   </span></li><li class="alt"><span>                        aliasType = PropertyUtils.getProperty(entity, alias).getClass().getSimpleName();   </span></li><li class=""><span>                    } </span><span class="keyword">catch</span><span> (Exception e) {   </span></li><li class="alt"><span>                        logger.error(</span><span class="string">"Get property"</span><span> + alias + </span><span class="string">" error"</span><span>);   </span></li><li class=""><span>                    }   </span></li><li class="alt"><span>                    criteria.createAlias(aliasType, alias);   </span></li><li class=""><span>                }   </span></li><li class="alt"><span>  </span></li><li class=""><span>                </span><span class="keyword">if</span><span> (</span><span class="string">"asc"</span><span>.equalsIgnoreCase(orderType)) {   </span></li><li class="alt"><span>                    criteria.addOrder(Order.asc(fieldName));   </span></li><li class=""><span>                } </span><span class="keyword">else</span><span> {   </span></li><li class="alt"><span>                    criteria.addOrder(Order.desc(fieldName));   </span></li><li class=""><span>                }   </span></li><li class="alt"><span>            }   </span></li><li class=""><span>        }   </span></li><li class="alt"><span>    }   </span></li><li class=""><span>  </span></li><li class="alt"><span>    </span><span class="comment">/** </span>  
</li><li class=""><span><span class="comment">     * 判断对象某列的值在数据库中不存在重复 </span> </span></li><li class="alt"><span><span class="comment">     * </span> </span></li><li class=""><span><span class="comment">     * @param names 在POJO里相对应的属性名,列组合时以逗号分割 </span> </span></li><li class="alt"><span><span class="comment"></span></span></li><li class=""><span><span class="comment">     *              如"name,loginid,password" </span> </span></li><li class="alt"><span><span class="comment">     */</span><span>  </span></span></li><li class=""><span>    </span><span class="keyword">public</span><span> </span><span class="keyword">boolean</span><span> isNotUnique(Object entity, String names) {   </span></li><li class="alt"><span>        Assert.hasText(names);   </span></li><li class=""><span>        Criteria criteria = getSession().createCriteria(entity.getClass()).setProjection(Projections.rowCount());   </span></li><li class="alt"><span>        String[] nameList = names.split(</span><span class="string">","</span><span>);   </span></li><li class=""><span>        </span><span class="keyword">try</span><span> {   </span></li><li class="alt"><span>            </span><span class="keyword">for</span><span> (String name : nameList) {   </span></li><li class=""><span>                criteria.add(Restrictions.eq(name, PropertyUtils.getProperty(entity, name)));   </span></li><li class="alt"><span>            }   </span></li><li class=""><span>  </span></li><li class="alt"><span>            String keyName = getSessionFactory().getClassMetadata(entity.getClass()).getIdentifierPropertyName();   </span></li><li class=""><span>            </span><span class="keyword">if</span><span> (keyName != </span><span class="keyword">null</span><span>) {   </span></li><li class="alt"><span>                Object id = PropertyUtils.getProperty(entity, keyName);   </span></li><li class=""><span>                </span><span class="comment">//如果是update,排除自身 </span><span>  </span></li><li class="alt"><span>                </span><span class="keyword">if</span><span> (id != </span><span class="keyword">null</span><span>)   </span></li><li class=""><span>                    criteria.add(Restrictions.not(Restrictions.eq(keyName, id)));   </span></li><li class="alt"><span>            }   </span></li><li class=""><span>        }   </span></li><li class="alt"><span>        </span><span class="keyword">catch</span><span> (Exception e) {   </span></li><li class=""><span>            logger.error(e.getMessage());   </span></li><li class="alt"><span>            </span><span class="keyword">return</span><span> </span><span class="keyword">false</span><span>;   </span></li><li class=""><span>        }   </span></li><li class="alt"><span>        </span><span class="keyword">return</span><span> ((Integer) criteria.uniqueResult()) &gt; </span><span class="number">0</span><span>;   </span></li><li class=""><span>    }   </span></li><li class="alt"><span>}   </span></li></ol></div></font><img src ="http://www.blogjava.net/19851985lili/aggbug/98475.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-02-07 08:45 <a href="http://www.blogjava.net/19851985lili/articles/98475.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate的缓存机制介绍</title><link>http://www.blogjava.net/19851985lili/articles/97629.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Fri, 02 Feb 2007 11:57:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/97629.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/97629.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/97629.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/97629.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/97629.html</trackback:ping><description><![CDATA[缓存是介于应用程序和物理数据源之间，其作用是为了降低应用程序对物理数据源访问的频次，从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制，应用程序在运行时从缓存读写数据，在特定的时刻或事件会同步缓存和物理数据源的数据。<br /><br />　　缓存的介质一般是内存，所以读写速度很快。但如果缓存中存放的数据量非常大时，也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质，还要考虑到管理缓存的并发访问和缓存数据的生命周期。<br /><br />　　Hibernate的缓存包括Session的缓存和SessionFactory的缓存，其中SessionFactory的缓存又可以分为两类：内置缓存和外置缓存。Session的缓存是内置的，不能被卸载，也被称为Hibernate的第一级缓存。SessionFactory的内置缓存和Session的缓存在实现方式上比较相似，前者是SessionFactory对象的一些集合属性包含的数据，后者是指Session的一些集合属性包含的数据。SessionFactory的内置缓存中存放了映射元数据和预定义SQL语句，映射元数据是映射文件中数据的拷贝，而预定义SQL语句是在Hibernate初始化阶段根据映射元数据推导出来，SessionFactory的内置缓存是只读的，应用程序不能修改缓存中的映射元数据和预定义SQL语句，因此SessionFactory不需要进行内置缓存与映射文件的同步。SessionFactory的外置缓存是一个可配置的插件。在默认情况下，SessionFactory不会启用这个插件。外置缓存的数据是数据库数据的拷贝，外置缓存的介质可以是内存或者硬盘。SessionFactory的外置缓存也被称为Hibernate的第二级缓存。<br /><br />　　Hibernate的这两级缓存都位于持久化层，存放的都是数据库数据的拷贝，那么它们之间的区别是什么呢？为了理解二者的区别，需要深入理解持久化层的缓存的两个特性：缓存的范围和缓存的并发访问策略。<br /><br />持久化层的缓存的范围<br /><br />　　缓存的范围决定了缓存的生命周期以及可以被谁访问。缓存的范围分为三类。<br /><br />　　1 事务范围：缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期，当事务结束时，缓存也就结束生命周期。在此范围下，缓存的介质是内存。事务可以是数据库事务或者应用事务，每个事务都有独自的缓存，缓存内的数据通常采用相互关联的的对象形式。<br /><br />　　2 进程范围：缓存被进程内的所有事务共享。这些事务有可能是并发访问缓存，因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进程的生命周期，进程结束时，缓存也就结束了生命周期。进程范围的缓存可能会存放大量的数据，所以存放的介质可以是内存或硬盘。缓存内的数据既可以是相互关联的对象形式也可以是对象的松散数据形式。松散的对象数据形式有点类似于对象的序列化数据，但是对象分解为松散的算法比对象序列化的算法要求更快。<br /><br />　　3 集群范围：在集群环境中，缓存被一个机器或者多个机器的进程共享。缓存中的数据被复制到集群环境中的每个进程节点，进程间通过远程通信来保证缓存中的数据的一致性，缓存中的数据通常采用对象的松散数据形式。<br /><br />　　对大多数应用来说，应该慎重地考虑是否需要使用集群范围的缓存，因为访问的速度不一定会比直接访问数据库数据的速度快多少。<br /><br />　　持久化层可以提供多种范围的缓存。如果在事务范围的缓存中没有查到相应的数据，还可以到进程范围或集群范围的缓存内查询，如果还是没有查到，那么只有到数据库中查询。事务范围的缓存是持久化层的第一级缓存，通常它是必需的；进程范围或集群范围的缓存是持久化层的第二级缓存，通常是可选的。<br /><br />持久化层的缓存的并发访问策略<br /><br />　　当多个并发的事务同时访问持久化层的缓存的相同数据时，会引起并发问题，必须采用必要的事务隔离措施。<br /><br />　　在进程范围或集群范围的缓存，即第二级缓存，会出现并发问题。因此可以设定以下四种类型的并发访问策略，每一种策略对应一种事务隔离级别。<br /><br />　　事务型：仅仅在受管理环境中适用。它提供了Repeatable Read事务隔离级别。对于经常被读但很少修改的数据，可以采用这种隔离类型，因为它可以防止脏读和不可重复读这类的并发问题。<br /><br />　　读写型：提供了Read Committed事务隔离级别。仅仅在非集群的环境中适用。对于经常被读但很少修改的数据，可以采用这种隔离类型，因为它可以防止脏读这类的并发问题。<br /><br />　　非严格读写型：不保证缓存与数据库中数据的一致性。如果存在两个事务同时访问缓存中相同数据的可能，必须为该数据配置一个很短的数据过期时间，从而尽量避免脏读。对于极少被修改，并且允许偶尔脏读的数据，可以采用这种并发访问策略。<br /><br />　　只读型：对于从来不会修改的数据，如参考数据，可以使用这种并发访问策略。<br /><br />　　事务型并发访问策略是事务隔离级别最高，只读型的隔离级别最低。事务隔离级别越高，并发性能就越低。<br /><br />什么样的数据适合存放到第二级缓存中？<br /><img src ="http://www.blogjava.net/19851985lili/aggbug/97629.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-02-02 19:57 <a href="http://www.blogjava.net/19851985lili/articles/97629.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate主键生成方式</title><link>http://www.blogjava.net/19851985lili/articles/97627.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Fri, 02 Feb 2007 11:53:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/97627.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/97627.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/97627.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/97627.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/97627.html</trackback:ping><description><![CDATA[
		<div class="tit">Hibernate主键生成方式</div>
		<div class="date">2006-11-23 01:35</div>
		<table style="TABLE-LAYOUT: fixed">
				<tbody>
						<tr>
								<td>
										<div class="cnt">
												<div class="postText">
														<strong>Key Generator<br />主键产生器<br />可选项说明：<br />1) assigned<br />主键由外部程序负责生成，无需Hibernate参与。<br /><br />2) hilo<br />通过hi/lo 算法实现的主键生成机制，需要额外的数据库表保存主<br />键生成历史状态。<br /><br />3) seqhilo<br />与hilo 类似，通过hi/lo 算法实现的主键生成机制，只是主键历史<br />状态保存在Sequence中，适用于支持Sequence的数据库，如Oracle。<br /><br />4) increment<br />主键按数值顺序递增。此方式的实现机制为在当前应用实例中维持<br />一个变量，以保存着当前的最大值，之后每次需要生成主键的时候<br />将此值加1作为主键。<br />这种方式可能产生的问题是：如果当前有多个实例访问同一个数据<br />库，那么由于各个实例各自维护主键状态，不同实例可能生成同样<br />的主键，从而造成主键重复异常。因此，如果同一数据库有多个实<br />例访问，此方式必须避免使用。<br /><br />5) identity<br />采用数据库提供的主键生成机制。如DB2、SQL Server、MySQL<br />中的主键生成机制。<br /><br />6) sequence<br />采用数据库提供的sequence 机制生成主键。如Oralce 中的<br />Sequence。<br /><br />7) native<br />由Hibernate根据底层数据库自行判断采用identity、hilo、sequence<br />其中一种作为主键生成方式。<br /><br />8) uuid.hex<br />由Hibernate基于128 位唯一值产生算法生成16 进制数值（编码后<br />以长度32 的字符串表示）作为主键。<br /><br />9) uuid.string<br />与uuid.hex 类似，只是生成的主键未进行编码（长度16）。在某些<br />数据库中可能出现问题（如PostgreSQL）。<br /><br />10) foreign<br />使用外部表的字段作为主键。<br />一般而言，利用uuid.hex方式生成主键将提供最好的性能和数据库平台适<br />应性。<br /><br />另外由于常用的数据库，如Oracle、DB2、SQLServer、MySql 等，都提<br />供了易用的主键生成机制（Auto-Increase 字段或者Sequence）。我们可以在数<br />据库提供的主键生成机制上，采用generator-class=native的主键生成方式。<br />不过值得注意的是，一些数据库提供的主键生成机制在效率上未必最佳，<br />大量并发insert数据时可能会引起表之间的互锁。<br />数据库提供的主键生成机制，往往是通过在一个内部表中保存当前主键状<br />态（如对于自增型主键而言，此内部表中就维护着当前的最大值和递增量），<br />之后每次插入数据会读取这个最大值，然后加上递增量作为新记录的主键，之<br />后再把这个新的最大值更新回内部表中，这样，一次Insert操作可能导致数据<br />库内部多次表读写操作，同时伴随的还有数据的加锁解锁操作，这对性能产生<br />了较大影响。<br />因此，对于并发Insert要求较高的系统，推荐采用uuid.hex 作为主键生成<br />机制。 </strong>
												</div>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.blogjava.net/19851985lili/aggbug/97627.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-02-02 19:53 <a href="http://www.blogjava.net/19851985lili/articles/97627.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate的一对多关联实例 </title><link>http://www.blogjava.net/19851985lili/articles/95455.html</link><dc:creator>☜♥☞MengChuChen</dc:creator><author>☜♥☞MengChuChen</author><pubDate>Tue, 23 Jan 2007 01:35:00 GMT</pubDate><guid>http://www.blogjava.net/19851985lili/articles/95455.html</guid><wfw:comment>http://www.blogjava.net/19851985lili/comments/95455.html</wfw:comment><comments>http://www.blogjava.net/19851985lili/articles/95455.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/19851985lili/comments/commentRss/95455.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/19851985lili/services/trackbacks/95455.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: Hibernate2.1.8中有关一对多的文档，可以查看官方网站上的文档：http://www.hibernate.org/hib_docs/reference/zh-cn/html/，由于篇幅太长，这里就不再引用。      我的例子是一个全国省和市的数据表，省为一个表，市为一个表，所使用的数据库是MySQL 4.1.11。表的结构如下： 1CREATE TABLE IF NOT EXISTS ...&nbsp;&nbsp;<a href='http://www.blogjava.net/19851985lili/articles/95455.html'>阅读全文</a><img src ="http://www.blogjava.net/19851985lili/aggbug/95455.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/19851985lili/" target="_blank">☜♥☞MengChuChen</a> 2007-01-23 09:35 <a href="http://www.blogjava.net/19851985lili/articles/95455.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>