﻿<?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-lanxin1020-随笔分类-hibernate</title><link>http://www.blogjava.net/lanxin1020/category/38968.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 25 May 2009 09:50:55 GMT</lastBuildDate><pubDate>Mon, 25 May 2009 09:50:55 GMT</pubDate><ttl>60</ttl><item><title>hibernate 自定义数据类型映射（转）</title><link>http://www.blogjava.net/lanxin1020/archive/2009/05/24/277716.html</link><dc:creator>lanxin1020</dc:creator><author>lanxin1020</author><pubDate>Sun, 24 May 2009 11:57:00 GMT</pubDate><guid>http://www.blogjava.net/lanxin1020/archive/2009/05/24/277716.html</guid><wfw:comment>http://www.blogjava.net/lanxin1020/comments/277716.html</wfw:comment><comments>http://www.blogjava.net/lanxin1020/archive/2009/05/24/277716.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lanxin1020/comments/commentRss/277716.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lanxin1020/services/trackbacks/277716.html</trackback:ping><description><![CDATA[UserType and CompositeUserType为<span class="hilite1">Hibernate</span>中提供的用户类型自定义接口。根据这个接口，可以实现自定义的数据类型。&nbsp;<br />
<br />
最近看&lt;&lt;深入浅出<span class="hilite1">Hibernate</span>&gt;&gt;,作者在书中介绍了<span class="hilite1">Hibernate</span> 提供的用户自定义数据类型，于是效仿书中的方法，在数据库表中添加一个字段用于记录所有好友的userid，每个userid之间用";"加以分隔，同时将该字段映射为一个特殊的List集合，利用UserType interface实现String解析后将各个userid封装在List中，将List中的记录封装成以";"分隔的String。 <br />
使用UserType接口，实现了较好的设计风格，以及更好的重用性。 <br />
/* <br />
* 用户自定义的数据类型，对应数据库中的一个字段，在该字段中，保存了 <br />
* 多个用户需要的信息，之间用";"加以分隔. <br />
* @Author:Paul <br />
* @Date:April 18th,2008 <br />
*/ <br />
package com.globalhands.<span class="hilite1">hibernate</span>.userTypes; <br />
<br />
import java.io.Serializable; <br />
import java.sql.PreparedStatement; <br />
import java.sql.ResultSet; <br />
import java.sql.SQLException; <br />
import java.util.ArrayList; <br />
import java.util.List; <br />
import java.sql.Types; <br />
<br />
import org.<span class="hilite1">hibernate</span>.<span class="hilite1">Hibernate</span>; <br />
import org.<span class="hilite1">hibernate</span>.HibernateException; <br />
import org.<span class="hilite1">hibernate</span>.usertype.UserType; <br />
<br />
public class SpecialList implements UserType { <br />
private List specialList; <br />
<br />
private static final char SPLITTER = ';'; <br />
<br />
private static final int[] TYPES = new int[] { Types.VARCHAR }; <br />
<br />
public String assemble(Serializable arg0, Object arg1) <br />
throws HibernateException { <br />
return null; <br />
} <br />
<br />
/* <br />
* 将List封装为一个String对象 <br />
*/ <br />
public String assemble(List specialList) throws HibernateException { <br />
StringBuffer sb = new StringBuffer(); <br />
for (int i = 0; i &lt; specialList.size() - 1; i++) { <br />
sb.append(specialList.get(i)).append(this.SPLITTER); <br />
} <br />
sb.append(specialList.get(specialList.size() - 1)); <br />
return sb.toString(); <br />
} <br />
<br />
/* <br />
* 创建一个新的List实例，包含原有的List实例中的所有元素. <br />
*/ <br />
public Object deepCopy(Object value) throws HibernateException { <br />
List sourceList = (List) value; <br />
List targetList = new ArrayList(); <br />
targetList.addAll(sourceList); <br />
return targetList; <br />
} <br />
<br />
public Serializable disassemble(Object arg0) throws HibernateException { <br />
return null; <br />
} <br />
<br />
/* <br />
* 判断specialList是否发生变化 <br />
*/ <br />
public boolean equals(Object x, Object y) throws HibernateException { <br />
if (x == y) { <br />
return true; <br />
} <br />
if (x != null &amp;&amp; y != null) { <br />
List xList = (List) x; <br />
List yList = (List) y; <br />
<br />
if (xList.size() != yList.size()) { <br />
return false; <br />
} <br />
<br />
for (int i = 0; i &lt;= xList.size() - 1; i++) { <br />
String str1 = (String) xList.get(i); <br />
String str2 = (String) yList.get(i); <br />
if (!xList.equals(yList)) { <br />
return false; <br />
} <br />
} <br />
return true; <br />
} <br />
return false; <br />
} <br />
<br />
public int hashCode(Object arg0) throws HibernateException { <br />
return 0; <br />
} <br />
<br />
public boolean isMutable() { <br />
return false; <br />
} <br />
<br />
/* <br />
* 从resultset中取出email字段，并将其解析为List类型后返回 <br />
*/ <br />
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) <br />
throws HibernateException, SQLException { <br />
String value = (String) <span class="hilite1">Hibernate</span>.STRING.nullSafeGet(rs, names[0]); <br />
if (value != null) { <br />
return parse(value); <br />
} else { <br />
return null; <br />
} <br />
} <br />
<br />
/* <br />
* 将以";"分隔的字符串解析为一个字符串数组 <br />
*/ <br />
private List parse(String value) { <br />
String[] strs = value.split(";"); <br />
List specialList = new ArrayList(); <br />
for (int i = 0; i &lt;= strs.length - 1; i++) { <br />
specialList.add(strs[i]); <br />
} <br />
return specialList; <br />
} <br />
<br />
/* <br />
* 将List型的email信息组装成字符串之后保存到email字段 <br />
*/ <br />
public void nullSafeSet(PreparedStatement st, Object value, int index) <br />
throws HibernateException, SQLException { <br />
if (value != null) { <br />
String str = assemble((List) value); <br />
<span class="hilite1">Hibernate</span>.STRING.nullSafeSet(st, str, index); <br />
} else { <br />
<span class="hilite1">Hibernate</span>.STRING.nullSafeSet(st, value, index); <br />
} <br />
} <br />
<br />
public Object replace(Object arg0, Object arg1, Object arg2) <br />
throws HibernateException { <br />
return null; <br />
} <br />
<br />
public Class returnedClass() { <br />
return List.class; <br />
} <br />
<br />
public int[] sqlTypes() { <br />
return TYPES; <br />
} <br />
<br />
} <br />
同时，修改相应的[ormapping_filename].hbm.xml中相应字段的映射信息 <br />
&lt;property name="buddy" <strong>type="com.globalhands.<span class="hilite1">hibernate</span>.userTypes.SpecialList"&gt;</strong> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;column name="buddy" length="2000" not-null="true" /&gt; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt; <br />
之后，修改POJO类中该字段的返回类型为List。 <br />
使用JUnit测试程序。 <br />
<img src ="http://www.blogjava.net/lanxin1020/aggbug/277716.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lanxin1020/" target="_blank">lanxin1020</a> 2009-05-24 19:57 <a href="http://www.blogjava.net/lanxin1020/archive/2009/05/24/277716.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate悲观锁和乐观锁(转)</title><link>http://www.blogjava.net/lanxin1020/archive/2009/04/12/265131.html</link><dc:creator>lanxin1020</dc:creator><author>lanxin1020</author><pubDate>Sun, 12 Apr 2009 08:12:00 GMT</pubDate><guid>http://www.blogjava.net/lanxin1020/archive/2009/04/12/265131.html</guid><wfw:comment>http://www.blogjava.net/lanxin1020/comments/265131.html</wfw:comment><comments>http://www.blogjava.net/lanxin1020/archive/2009/04/12/265131.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lanxin1020/comments/commentRss/265131.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lanxin1020/services/trackbacks/265131.html</trackback:ping><description><![CDATA[<div class="blog_title">
<div class="date"><a href="/blog/232171"><span class="hilite1">Hibernate</span>悲观锁和乐观锁</a></div>
</div>
<div class="blog_content">（转）<span class="hilite1">Hibernate</span>支持两种锁机制： <br />
即通常所说的&#8220;悲观锁（Pessimistic Locking）&#8221;和 <br />
&#8220;乐观锁（OptimisticLocking）&#8221;。 <br />
悲观锁的实现，往往依靠数据库提供的锁机制（也只有数据库层提供的锁机制才能真正保证数据访问的排他性，否则，即使在本系统中实现了加锁机制，也无法保证外部系统不会修改数据）。 <br />
<span class="hilite1">Hibernate</span>的加锁模式有： <br />
&#216; LockMode.NONE ： 无锁机制。 <br />
&#216; LockMode.WRITE ：<span class="hilite1">Hibernate</span>在Insert和Update记录的时候会自动 <br />
获取。 <br />
&#216; LockMode.READ ： <span class="hilite1">Hibernate</span>在读取记录的时候会自动获取。 <br />
以上这三种锁机制一般由<span class="hilite1">Hibernate</span>内部使用，如<span class="hilite1">Hibernate</span>为了保证Update <br />
过程中对象不会被外界修改，会在save方法实现中自动为目标对象加上WRITE锁。 <br />
&#216; LockMode.UPGRADE ：利用数据库的for update子句加锁。 <br />
&#216; LockMode. UPGRADE_NOWAIT ：Oracle的特定实现，利用Oracle的for <br />
update nowait子句实现加锁。 <br />
乐观锁，大多是基于数据版本（Version）记录机制实现。何谓数据版本？即为数据增加一个版本标识，在基于数据库表的版本解决方案中，一般是通过为数据库表增加一个&#8220;version&#8221;字段来实现。读取出数据时，将此版本号一同读出，之后更新时，对此版本号加一。此时，将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对，如果提交的数据版本号大于数据库表当前版本号，则予以更新，否则认为是过期数据。 <br />
悲观锁与乐观锁的比较: <br />
悲观锁大多数情况下依靠数据库的锁机制实现，以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销，特别是对长事务而言，这样的开销往往无法承受; <br />
相对悲观锁而言，乐观锁机制采取了更加宽松的加锁机制。乐观锁机制往往基于系统中的数据存储逻辑，因此也具备一定的局限性，如在上例中，由于乐观锁机制是在我们的系统中实现，来自外部系统的更新操作不受我们系统的控制，因此可能会造成脏数据被更新到数据库中。在 <br />
系统设计阶段，我们应该充分考虑到这些情况出现的可能性，并进行相应调整（如将乐观锁策略在数据库存储过程中实现，对外只开放基于此存储过程的数据更新途径，而不是将数据库表直接对外公开）。 <br />
<span class="hilite1">Hibernate</span> 在其数据访问引擎中内置了乐观锁实现。如果不用考虑外部系统对数据库的更新操作，利用<span class="hilite1">Hibernate</span>提供的透明化乐观锁实现，将大大提升我们的生产力。 <br />
<span class="hilite1">Hibernate</span>中可以通过class描述符的optimistic-lock属性结合version描述符指定。 <br />
optimistic-lock属性有如下可选取值： <br />
&#216; none <br />
无乐观锁 <br />
&#216; version <br />
通过版本机制实现乐观锁 <br />
&#216; dirty <br />
通过检查发生变动过的属性实现乐观锁 <br />
&#216; all <br />
通过检查所有属性实现乐观锁 <br />
其中通过version实现的乐观锁机制是<span class="hilite1">Hibernate</span>官方推荐的乐观锁实现，同时也是<span class="hilite1">Hibernate</span>中，目前唯一在数据对象脱离 Session发生修改的情况下依然有效的锁机制。因此，一般情况下，我们都选择version方式作为<span class="hilite1">Hibernate</span>乐观锁实现机制。 </div>
 <img src ="http://www.blogjava.net/lanxin1020/aggbug/265131.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lanxin1020/" target="_blank">lanxin1020</a> 2009-04-12 16:12 <a href="http://www.blogjava.net/lanxin1020/archive/2009/04/12/265131.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用 SchemaExport 自动建表 </title><link>http://www.blogjava.net/lanxin1020/archive/2009/04/11/265021.html</link><dc:creator>lanxin1020</dc:creator><author>lanxin1020</author><pubDate>Sat, 11 Apr 2009 08:31:00 GMT</pubDate><guid>http://www.blogjava.net/lanxin1020/archive/2009/04/11/265021.html</guid><wfw:comment>http://www.blogjava.net/lanxin1020/comments/265021.html</wfw:comment><comments>http://www.blogjava.net/lanxin1020/archive/2009/04/11/265021.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lanxin1020/comments/commentRss/265021.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lanxin1020/services/trackbacks/265021.html</trackback:ping><description><![CDATA[<div class="postTitle"><a id="viewpost1_TitleUrl" class="postTitle2" href="http://www.blogjava.net/hijeff/archive/2007/03/21/105125.html">使用 SchemaExport 自动建表</a> </div>
<p>使用Hibernate自带的工具<em>hbm2ddl</em>，建立根据你的对象建立数据库:</p>
<p>首先建好POJO object, XML Mapping File(也可以使用工具根据POJO class建立)，配置文件(hibernate.cfg.xml)</p>
<p>Java代码</p>
<br />
<pre xml:space="preserve">import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
<br />
public class SchemaUtil {<br />
public static void main(String[] args) {<br />
<br />
Configuration cfg = new Configuration().configure();
SchemaExport schemaExport= new SchemaExport(cfg);
schemaExport.create(false, true);
}
}
</pre>
<img src ="http://www.blogjava.net/lanxin1020/aggbug/265021.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lanxin1020/" target="_blank">lanxin1020</a> 2009-04-11 16:31 <a href="http://www.blogjava.net/lanxin1020/archive/2009/04/11/265021.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SchemaExportTask(转自 良葛格)</title><link>http://www.blogjava.net/lanxin1020/archive/2009/04/11/265001.html</link><dc:creator>lanxin1020</dc:creator><author>lanxin1020</author><pubDate>Sat, 11 Apr 2009 03:37:00 GMT</pubDate><guid>http://www.blogjava.net/lanxin1020/archive/2009/04/11/265001.html</guid><wfw:comment>http://www.blogjava.net/lanxin1020/comments/265001.html</wfw:comment><comments>http://www.blogjava.net/lanxin1020/archive/2009/04/11/265001.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lanxin1020/comments/commentRss/265001.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lanxin1020/services/trackbacks/265001.html</trackback:ping><description><![CDATA[<p>在您撰寫好*.hbm.xml映射文件之後，您可以使用 net.sf.hibernate.tool.hbm2ddl.SchemaExportTask來自動建立資料庫表格，這邊所使用的方式是結合Ant進行自動化建構，首先我們假設將使用以下的User.hbm.xml： </p>
<div style="border-bottom-style: solid; border-right-style: solid; border-top-style: solid; border-left-style: solid" class="code">
<div style="border-bottom-style: solid" class="codeHeader"><strong>User.hbm.xml</strong></div>
<div class="codeContent">
<pre class="code-java">&lt;?xml version=<span class="code-quote">"1.0"</span>?&gt;
&lt;!DOCTYPE hibernate-mapping
PUBLIC <span class="code-quote">"-<span class="code-comment">//Hibernate/Hibernate Mapping DTD//EN"</span>
</span>    <span class="code-quote">"http:<span class="code-comment">//hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"</span>&gt;
</span>
&lt;hibernate-mapping&gt;
&lt;class name=<span class="code-quote">"onlyfun.caterpillar.User"</span> table=<span class="code-quote">"USER"</span>&gt;
&lt;id name=<span class="code-quote">"id"</span> type=<span class="code-quote">"string"</span> unsaved-value=<span class="code-quote">"<span class="code-keyword">null</span>"</span>&gt;
&lt;column name=<span class="code-quote">"user_id"</span> sql-type=<span class="code-quote">"<span class="code-object">char</span>(32)"</span>/&gt;
&lt;generator class=<span class="code-quote">"uuid.hex"</span>/&gt;
&lt;/id&gt;
&lt;property name=<span class="code-quote">"name"</span> type=<span class="code-quote">"string"</span> not-<span class="code-keyword">null</span>=<span class="code-quote">"<span class="code-keyword">true</span>"</span>&gt;
&lt;column name=<span class="code-quote">"name"</span> length=<span class="code-quote">"16"</span> not-<span class="code-keyword">null</span>=<span class="code-quote">"<span class="code-keyword">true</span>"</span>/&gt;
&lt;/property&gt;
&lt;property name=<span class="code-quote">"sex"</span> type=<span class="code-quote">"<span class="code-object">char</span>"</span> /&gt;
&lt;property name=<span class="code-quote">"age"</span> type=<span class="code-quote">"<span class="code-object">int</span>"</span>/&gt;
&lt;/class&gt;
&lt;/hibernate-mapping&gt;</pre>
</div>
</div>
<p>　在這個映射文件中，&lt;column/&gt;標籤用於指定建立表格時的一些資訊，例如映射的表格欄位名稱，或是sql-type或 length等屬性，如果不指定這些資訊時，SchemaExportTask將自動使用Hibernate的類型至SQL類型等資訊來建立表格；sql -type用於指定表格欄位型態，not-null表示欄位不能為null，length則用於指定表格文字欄位長度，這些屬性的說明，都可以在 Hibernate參考手冊的表15.1找到。</p>
<p>　下面的build.xml用於Ant自動化建構時，生成資料庫表格之用：</p>
<div style="border-bottom-style: solid; border-right-style: solid; border-top-style: solid; border-left-style: solid" class="code">
<div style="border-bottom-style: solid" class="codeHeader"><strong>build.xml</strong></div>
<div class="codeContent">
<pre class="code-java">&lt;project name=<span class="code-quote">"Hibernate"</span> <span class="code-keyword">default</span>=<span class="code-quote">"schema"</span> basedir=<span class="code-quote">"."</span>&gt;
&lt;property name=<span class="code-quote">"source.root"</span> value=<span class="code-quote">"src"</span>/&gt;
&lt;property name=<span class="code-quote">"class.root"</span> value=<span class="code-quote">"classes"</span>/&gt;
&lt;property name=<span class="code-quote">"lib.dir"</span> value=<span class="code-quote">"lib"</span>/&gt;
&lt;property name=<span class="code-quote">"data.dir"</span> value=<span class="code-quote">"data"</span>/&gt;
&lt;path id=<span class="code-quote">"project.class.path"</span>&gt;
&lt;!-- Include our own classes, of course --&gt;
&lt;pathelement location=<span class="code-quote">"${class.root}"</span> /&gt;
&lt;!-- Include jars in the project library directory --&gt;
&lt;fileset dir=<span class="code-quote">"${lib.dir}"</span>&gt;
&lt;include name=<span class="code-quote">"*.jar"</span>/&gt;
&lt;/fileset&gt;
&lt;pathelement path =<span class="code-quote">"${classpath}"</span>/&gt;
&lt;/path&gt;
&lt;target name=<span class="code-quote">"schema"</span> description=<span class="code-quote">"Generate DB schema from the O/R mapping files"</span>&gt;
&lt;!-- Teach Ant how to use Hibernate's schema generation tool --&gt;
&lt;taskdef name=<span class="code-quote">"schemaexport"</span>
classname=<span class="code-quote">"net.sf.hibernate.tool.hbm2ddl.SchemaExportTask"</span>
classpathref=<span class="code-quote">"project.class.path"</span>/&gt;
&lt;schemaexport properties=<span class="code-quote">"${source.root}/hibernate.properties"</span>
quiet=<span class="code-quote">"no"</span> text=<span class="code-quote">"no"</span> drop=<span class="code-quote">"no"</span> delimiter=<span class="code-quote">";"</span>&gt;
&lt;fileset dir=<span class="code-quote">"${source.root}"</span>&gt;
&lt;include name=<span class="code-quote">"**/*.hbm.xml"</span>/&gt;
&lt;/fileset&gt;
&lt;/schemaexport&gt;
&lt;/target&gt;
&lt;/project&gt;</pre>
</div>
</div>
<p>　&lt;taskdef/&gt;標籤定義一個新的任務schemaexport，相關的屬性設定是根據參考手冊的建議設定的，我們在這邊使用 hibernate.properties來告訴SchemaExportTask相關的JDBC資訊，quiet、text等屬性的定義，可以看參考手冊的表15.2。</p>
<p>　這個Ant建構檔案，會找尋src目錄下包括子目錄中有的*.hbm.xml，並自動根據映射資訊建立表格，我們還必須提供hibernate.properties（置於src下）來告知JDBC連接的相關訊息：</p>
<div style="border-bottom-style: solid; border-right-style: solid; border-top-style: solid; border-left-style: solid" class="code">
<div style="border-bottom-style: solid" class="codeHeader"><strong>hibernate.properties</strong></div>
<div class="codeContent">
<pre class="code-java">hibernate.dialect=net.sf.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql:<span class="code-comment">//localhost/HibernateTest
</span>hibernate.connection.username=caterpillar
hibernate.connection.password=123456</pre>
</div>
</div>
<p>　這邊使用的是MySQL，請實際根據您所使用的資料庫設定dialect、驅動程式等資訊，在開始運行Ant使用SchemaExportTask進行自動表格建立之前，您要先建立資料庫，這邊的例子則是在MySQL中先建立HibernateTest：</p>
<div style="border-bottom-style: solid; border-right-style: solid; border-top-style: solid; border-left-style: solid" class="code">
<div class="codeContent">
<pre class="code-java">mysql&gt; create database HibernateTest;
Query OK, 1 row affected (0.03 sec)</pre>
</div>
</div>
<p>　接著就可以運行Ant了，執行結果如下：</p>
<div style="border-bottom-style: solid; border-right-style: solid; border-top-style: solid; border-left-style: solid" class="code">
<div class="codeContent">
<pre class="code-java">ant
Buildfile: build.xml
schema:
[schemaexport] log4j:WARN No appenders could be found <span class="code-keyword">for</span> logger (net.sf.hiberna
te.cfg.Environment).
[schemaexport] log4j:WARN Please initialize the log4j system properly.
[schemaexport] drop table <span class="code-keyword">if</span> exists USER;
[schemaexport] create table USER (
[schemaexport]    user_id <span class="code-object">char</span>(32) not <span class="code-keyword">null</span>,
[schemaexport]    name varchar(16) not <span class="code-keyword">null</span>,
[schemaexport]    sex <span class="code-object">char</span>(1),
[schemaexport]    age integer,
[schemaexport]    primary key (user_id)
[schemaexport] );
BUILD SUCCESSFUL
Total time: 5 seconds</pre>
</div>
</div>
<p>　運行的過程中，我們可以看到建立表格的SQL語句，而自動建立好的資料庫表格資訊如下：</p>
<div style="border-bottom-style: solid; border-right-style: solid; border-top-style: solid; border-left-style: solid" class="code">
<div class="codeContent">
<pre class="code-java">mysql&gt; DESCRIBE user;
+---------+-------------+------+-----+---------+-------+
| Field   | Type        | Null | Key | Default | Extra |
+---------+-------------+------+-----+---------+-------+
| user_id | varchar(32) |      | PRI |         |       |
| name    | varchar(16) |      |     |         |       |
| sex     | <span class="code-object">char</span>(1)     | YES  |     | NULL    |       |
| age     | <span class="code-object">int</span>(11)     | YES  |     | NULL    |       |
+---------+-------------+------+-----+---------+-------+
4 rows in set (0.04 sec)</pre>
</div>
</div>
<p>更多有關SchemaExportTask的資訊，可以看看參考手冊的第15章工具箱指南的部份。</p>
 <img src ="http://www.blogjava.net/lanxin1020/aggbug/265001.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lanxin1020/" target="_blank">lanxin1020</a> 2009-04-11 11:37 <a href="http://www.blogjava.net/lanxin1020/archive/2009/04/11/265001.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate延迟加载机制(转)</title><link>http://www.blogjava.net/lanxin1020/archive/2009/04/11/264987.html</link><dc:creator>lanxin1020</dc:creator><author>lanxin1020</author><pubDate>Sat, 11 Apr 2009 02:35:00 GMT</pubDate><guid>http://www.blogjava.net/lanxin1020/archive/2009/04/11/264987.html</guid><wfw:comment>http://www.blogjava.net/lanxin1020/comments/264987.html</wfw:comment><comments>http://www.blogjava.net/lanxin1020/archive/2009/04/11/264987.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lanxin1020/comments/commentRss/264987.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lanxin1020/services/trackbacks/264987.html</trackback:ping><description><![CDATA[延迟加载： <br />
&nbsp; 延迟加载机制是为了避免一些无谓的性能开销而提出来的，所谓延迟加载就是当在真正需要数据的时候，才真正执行数据加载操作。在Hibernate中提供了对实体对象的延迟加载以及对集合的延迟加载，另外在Hibernate3中还提供了对属性的延迟加载。下面我们就分别介绍这些种类的延迟加载的细节。 <br />
<span style="color: green">A、实体对象的延迟加载：</span> <br />
如果想对实体对象使用延迟加载，必须要在实体的映射配置文件中进行相应的配置，如下所示： <br />
&lt;hibernate-mapping&gt; <br />
&lt;class name=&#8221;com.neusoft.entity.User&#8221; table=&#8221;user&#8221; <span style="color: red">lazy=&#8221;true&#8221;&gt;</span> <br />
&nbsp;&nbsp; &#8230;&#8230; <br />
&lt;/class&gt; <br />
&lt;/hibernate-mapping&gt; <br />
通过将class的lazy属性设置为true，来开启实体的延迟加载特性。如果我们运行下面的代码： <br />
User user=(User)session.load(User.class,&#8221;1&#8221;);（1） <br />
System.out.println(user.getName());（2） <br />
当运行到(1)处时，Hibernate并没有发起对数据的查询，如果我们此时通过一些调试工具(比如JBuilder2005的Debug工具)，观察此时user对象的内存快照，我们会惊奇的发现，此时返回的可能是User$EnhancerByCGLIB$$bede8986类型的对象，而且其属性为null,这是怎么回事？还记得前面我曾讲过session.load()方法，会返回实体对象的代理类对象，这里所返回的对象类型就是User对象的代理类对象。在Hibernate中通过使用CGLIB,来实现动态构造一个目标对象的代理类对象，并且在代理类对象中包含目标对象的所有属性和方法，而且所有属性均被赋值为null。通过调试器显示的内存快照，我们可以看出此时真正的User对象，是包含在代理对象的CGLIB$CALBACK_0.target属性中，当代码运行到（2）处时，此时调用user.getName()方法，这时通过CGLIB赋予的回调机制，实际上调用CGLIB$CALBACK_0.getName()方法，当调用该方法时，Hibernate会首先检查CGLIB$CALBACK_0.target属性是否为null，如果不为空，则调用目标对象的getName方法，如果为空，则会发起数据库查询，生成类似这样的SQL语句：select * from user where id=&#8217;1&#8217;;来查询数据，并构造目标对象，并且将它赋值到CGLIB$CALBACK_0.target属性中。 <br />
&nbsp;&nbsp; 这样，通过一个中间代理对象，Hibernate实现了实体的延迟加载，只有当用户真正发起获得实体对象属性的动作时，才真正会发起数据库查询操作。所以实体的延迟加载是用通过中间代理类完成的，所以只有session.load()方法才会利用实体延迟加载，因为只有session.load()方法才会返回实体类的代理类对象。 <br />
<span style="color: green">B、&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 集合类型的延迟加载：</span> <br />
在Hibernate的延迟加载机制中，针对集合类型的应用，意义是最为重大的，因为这有可能使性能得到大幅度的提高，为此Hibernate进行了大量的努力，其中包括对JDK Collection的独立实现，我们在一对多关联中，定义的用来容纳关联对象的Set集合，并不是java.util.Set类型或其子类型，而是net.sf.hibernate.collection.Set类型，通过使用自定义集合类的实现，Hibernate实现了集合类型的延迟加载。为了对集合类型使用延迟加载，我们必须如下配置我们的实体类的关于关联的部分： <br />
&lt;hibernate-mapping&gt; <br />
&nbsp;&nbsp; &lt;class name=&#8221;com.neusoft.entity.User&#8221; table=&#8221;user&#8221;&gt; <br />
&#8230;.. <br />
&lt;set name=&#8221;addresses&#8221; table=&#8221;address&#8221; lazy=&#8221;true&#8221; inverse=&#8221;true&#8221;&gt; <br />
&lt;key column=&#8221;user_id&#8221;/&gt; <br />
&lt;one-to-many class=&#8221;com.neusoft.entity.Arrderss&#8221;/&gt; <br />
&lt;/set&gt; <br />
&nbsp;&nbsp; &lt;/class&gt; <br />
&lt;/hibernate-mapping&gt; <br />
通过将&lt;set&gt;元素的lazy属性设置为true来开启集合类型的延迟加载特性。我们看下面的代码： <br />
User user=(User)session.load(User.class,&#8221;1&#8221;); <br />
Collection addset=user.getAddresses();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (1) <br />
Iterator it=addset.iterator();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (2) <br />
while(it.hasNext()){ <br />
Address address=(Address)it.next(); <br />
System.out.println(address.getAddress()); <br />
} <br />
当程序执行到(1)处时，这时并不会发起对关联数据的查询来加载关联数据，只有运行到(2)处时，真正的数据读取操作才会开始，这时Hibernate会根据缓存中符合条件的数据索引，来查找符合条件的实体对象。 <br />
这里我们引入了一个全新的概念——数据索引，下面我们首先将接一下什么是数据索引。在Hibernate中对集合类型进行缓存时，是分两部分进行缓存的，首先缓存集合中所有实体的id列表，然后缓存实体对象，这些实体对象的id列表，就是所谓的数据索引。当查找数据索引时，如果没有找到对应的数据索引，这时就会一条select SQL的执行，获得符合条件的数据，并构造实体对象集合和数据索引，然后返回实体对象的集合，并且将实体对象和数据索引纳入Hibernate的缓存之中。另一方面，如果找到对应的数据索引，则从数据索引中取出id列表，然后根据id在缓存中查找对应的实体，如果找到就从缓存中返回，如果没有找到，在发起select SQL查询。在这里我们看出了另外一个问题，这个问题可能会对性能产生影响，这就是集合类型的缓存策略。如果我们如下配置集合类型： <br />
&lt;hibernate-mapping&gt; <br />
&nbsp;&nbsp; &lt;class name=&#8221;com.neusoft.entity.User&#8221; table=&#8221;user&#8221;&gt; <br />
&#8230;.. <br />
&lt;set name=&#8221;addresses&#8221; table=&#8221;address&#8221; <span style="color: red">lazy=&#8221;true&#8221;</span> inverse=&#8221;true&#8221;&gt; <br />
<span style="color: red">&lt;cache usage=&#8221;read-only&#8221;/&gt;</span>&lt;key column=&#8221;user_id&#8221;/&gt; <br />
&lt;one-to-many class=&#8221;com.neusoft.entity.Arrderss&#8221;/&gt; <br />
&lt;/set&gt; <br />
&nbsp;&nbsp; &lt;/class&gt; <br />
&lt;/hibernate-mapping&gt; <br />
这里我们应用了&lt;cache usage=&#8221;read-only&#8221;/&gt;配置，如果采用这种策略来配置集合类型，Hibernate将只会对数据索引进行缓存，而不会对集合中的实体对象进行缓存。如上配置我们运行下面的代码： <br />
User user=(User)session.load(User.class,&#8221;1&#8221;); <br />
Collection addset=user.getAddresses();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
Iterator it=addset.iterator();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
while(it.hasNext()){ <br />
Address address=(Address)it.next(); <br />
System.out.println(address.getAddress()); <br />
} <br />
System.out.println(&#8220;Second query&#8230;&#8230;&#8221;); <br />
User user2=(User)session.load(User.class,&#8221;1&#8221;); <br />
Collection it2=user2.getAddresses(); <br />
while(it2.hasNext()){ <br />
Address address2=(Address)it2.next(); <br />
System.out.println(address2.getAddress()); <br />
} <br />
运行这段代码，会得到类似下面的输出： <br />
Select * from user where id=&#8217;1&#8217;; <br />
Select * from address where user_id=&#8217;1&#8217;; <br />
Tianjin <br />
Dalian <br />
Second query&#8230;&#8230; <br />
Select * from address where id=&#8217;1&#8217;; <br />
Select * from address where id=&#8217;2&#8217;; <br />
Tianjin <br />
Dalian <br />
我们看到，当第二次执行查询时，执行了两条对address表的查询操作，为什么会这样？这是因为当第一次加载实体后，根据集合类型缓存策略的配置，只对集合数据索引进行了缓存，而并没有对集合中的实体对象进行缓存，所以在第二次再次加载实体时，Hibernate找到了对应实体的数据索引，但是根据数据索引，却无法在缓存中找到对应的实体，所以Hibernate根据找到的数据索引发起了两条select SQL的查询操作，这里造成了对性能的浪费，怎样才能避免这种情况呢？我们必须对集合类型中的实体也指定缓存策略，所以我们要如下对集合类型进行配置： <br />
&lt;hibernate-mapping&gt; <br />
&nbsp;&nbsp; &lt;class name=&#8221;com.neusoft.entity.User&#8221; table=&#8221;user&#8221;&gt; <br />
&#8230;.. <br />
&lt;set name=&#8221;addresses&#8221; table=&#8221;address&#8221; <span style="color: red">lazy=&#8221;true&#8221;</span> inverse=&#8221;true&#8221;&gt; <br />
<span style="color: red">&lt;cache usage=&#8221;read-write&#8221;/&gt;</span>&lt;key column=&#8221;user_id&#8221;/&gt; <br />
&lt;one-to-many class=&#8221;com.neusoft.entity.Arrderss&#8221;/&gt; <br />
&lt;/set&gt; <br />
&nbsp;&nbsp; &lt;/class&gt; <br />
&lt;/hibernate-mapping&gt; <br />
此时Hibernate会对集合类型中的实体也进行缓存，如果根据这个配置再次运行上面的代码，将会得到类似如下的输出： <br />
Select * from user where id=&#8217;1&#8217;; <br />
Select * from address where user_id=&#8217;1&#8217;; <br />
Tianjin <br />
Dalian <br />
Second query&#8230;&#8230; <br />
Tianjin <br />
Dalian <br />
这时将不会再有根据数据索引进行查询的SQL语句，因为此时可以直接从缓存中获得集合类型中存放的实体对象。 <br />
<span style="color: green">C、&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 属性延迟加载：</span> <br />
&nbsp; 在Hibernate3中，引入了一种新的特性——属性的延迟加载，这个机制又为获取高性能查询提供了有力的工具。在前面我们讲大数据对象读取时，在User对象中有一个resume字段，该字段是一个java.sql.Clob类型，包含了用户的简历信息，当我们加载该对象时，我们不得不每一次都要加载这个字段，而不论我们是否真的需要它，而且这种大数据对象的读取本身会带来很大的性能开销。在Hibernate2中，我们只有通过我们前面讲过的面性能的粒度细分，来分解User类，来解决这个问题（请参照那一节的论述），但是在Hibernate3中，我们可以通过属性延迟加载机制，来使我们获得只有当我们真正需要操作这个字段时，才去读取这个字段数据的能力，为此我们必须如下配置我们的实体类： <br />
&lt;hibernate-mapping&gt; <br />
&lt;class name=&#8221;com.neusoft.entity.User&#8221; table=&#8221;user&#8221;&gt; <br />
&#8230;&#8230; <br />
<span style="color: red">&lt;property name=&#8221;resume&#8221; type=&#8221;java.sql.Clob&#8221; column=&#8221;resume&#8221; lazy=&#8221;true&#8221;/&gt;</span>&nbsp;&nbsp; &lt;/class&gt; <br />
&lt;/hibernate-mapping&gt; <br />
通过对&lt;property&gt;元素的lazy属性设置true来开启属性的延迟加载，在Hibernate3中为了实现属性的延迟加载，使用了类增强器来对实体类的Class文件进行强化处理，通过增强器的增强，将CGLIB的回调机制逻辑，加入实体类，这里我们可以看出属性的延迟加载，还是通过CGLIB来实现的。CGLIB是Apache的一个开源工程，这个类库可以操纵java类的字节码，根据字节码来动态构造符合要求的类对象。根据上面的配置我们运行下面的代码： <br />
String sql=&#8221;from User user where user.name=&#8217;zx&#8217; &#8221;; <br />
Query query=session.createQuery(sql);&nbsp;&nbsp; (1) <br />
List list=query.list(); <br />
for(int i=0;i&lt;list.size();i++){ <br />
User user=(User)list.get(i); <br />
System.out.println(user.getName()); <br />
System.out.println(user.getResume());&nbsp;&nbsp; (2) <br />
} <br />
当执行到(1)处时，会生成类似如下的SQL语句： <br />
Select id,age,name from user where name=&#8217;zx&#8217;; <br />
这时Hibernate会检索User实体中所有非延迟加载属性对应的字段数据，当执行到(2)处时，会生成类似如下的SQL语句： <br />
Select resume from user where id=&#8217;1&#8217;; <br />
这时会发起对resume字段数据真正的读取操作。 <br />
 <img src ="http://www.blogjava.net/lanxin1020/aggbug/264987.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lanxin1020/" target="_blank">lanxin1020</a> 2009-04-11 10:35 <a href="http://www.blogjava.net/lanxin1020/archive/2009/04/11/264987.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate缓存机制（转）</title><link>http://www.blogjava.net/lanxin1020/archive/2009/04/11/264983.html</link><dc:creator>lanxin1020</dc:creator><author>lanxin1020</author><pubDate>Sat, 11 Apr 2009 02:24:00 GMT</pubDate><guid>http://www.blogjava.net/lanxin1020/archive/2009/04/11/264983.html</guid><wfw:comment>http://www.blogjava.net/lanxin1020/comments/264983.html</wfw:comment><comments>http://www.blogjava.net/lanxin1020/archive/2009/04/11/264983.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lanxin1020/comments/commentRss/264983.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lanxin1020/services/trackbacks/264983.html</trackback:ping><description><![CDATA[1.1.1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 基本的缓存原理 <br />
Hibernate缓存分为二级，第一级存放于session中称为一级缓存，默认带有且不能卸载。 <br />
<br />
<br />
<br />
第二级是由sessionFactory控制的进程级缓存。是全局共享的缓存，凡是会调用二级缓存的查询方法 都 <br />
<br />
会从中受益。只有经正确的配置后二级缓存才会发挥作用。同时在进行条件查询时必须使用相应的方法 <br />
<br />
才能从缓存中获取数据。比如Query.iterate()方法、load、get方法等。必须注意的是session.find方 <br />
<br />
法永远是从数据库中获取数据，不会从二级缓存中获取数据，即便其中有其所需要的数据也是如此。 <br />
<br />
<br />
<br />
查询时使用缓存的实现过程为：首先查询一级缓存中是否具有需要的数据，如果没有，查询二级缓存， <br />
<br />
如果二级缓存中也没有，此时再执行查询数据库的工作。要注意的是：此3种方式的查询速度是依次降低 <br />
<br />
的。 <br />
<br />
1.2.&nbsp;&nbsp; 存在的问题 <br />
1.2.1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 一级缓存的问题以及使用二级缓存的原因 <br />
&nbsp;&nbsp;&nbsp;&nbsp; 因为Session的生命期往往很短，存在于Session内部的第一级最快缓存的生命期当然也很短，所以 <br />
<br />
第一级缓存的命中率是很低的。其对系统性能的改善也是很有限的。当然，这个Session内部缓存的主要 <br />
<br />
作用是保持Session内部数据状态同步。并非是hibernate为了大幅提高系统性能所提供的。 <br />
<br />
为了提高使用hibernate的性能，除了常规的一些需要注意的方法比如： <br />
<br />
使用延迟加载、迫切外连接、查询过滤等以外，还需要配置hibernate的二级缓存。其对系统整体性能的 <br />
<br />
改善往往具有立竿见影的效果！ <br />
<br />
（经过自己以前作项目的经验，一般会有3~4倍的性能提高） <br />
<br />
<br />
<br />
1.2.2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; N+1次查询的问题 <br />
执行条件查询时，iterate（）方法具有著名的 &#8220;n+1&#8221;次查询的问题，也就是说在第一次查询时 <br />
<br />
iterate方法会执行满足条件的查询结果数再加一次（n+1）的查询。但是此问题只存在于第一次查询时 <br />
<br />
，在后面执行相同查询时性能会得到极大的改善。此方法适合于查询数据量较大的业务数据。 <br />
<br />
但是注意：当数据量特别大时（比如流水线数据等）需要针对此持久化对象配置其具体的缓存策略，比 <br />
<br />
如设置其存在于缓存中的最大记录数、缓存存在的时间等参数，以避免系统将大量的数据同时装载入内 <br />
<br />
存中引起内存资源的迅速耗尽，反而降低系统的性能！！！ <br />
<br />
<br />
<br />
1.3.&nbsp;&nbsp; 使用hibernate二级缓存的其他注意事项： <br />
1.3.1.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 关于数据的有效性 <br />
另外，hibernate会自行维护二级缓存中的数据，以保证缓存中的数据和数据库中的真实数据的一致性！ <br />
<br />
无论何时，当你调用save()、update()或 saveOrUpdate()方法传递一个对象时，或使用load()、 get() <br />
<br />
、list()、iterate() 或scroll()方法获得一个对象时, 该对象都将被加入到Session的内部缓存中。 <br />
<br />
当随后flush()方法被调用时，对象的状态会和数据库取得同步。 <br />
<br />
<br />
<br />
也就是说删除、更新、增加数据的时候，同时更新缓存。当然这也包括二级缓存！ <br />
<br />
<br />
<br />
只要是调用hibernate API执行数据库相关的工作。hibernate都会为你自动保证 缓存数据的有效性！！ <br />
<br />
<br />
<br />
但是，如果你使用了JDBC绕过hibernate直接执行对数据库的操作。此时，Hibernate不会/也不可能自行 <br />
<br />
感知到数据库被进行的变化改动，也就不能再保证缓存中数据的有效性！！ <br />
<br />
<br />
<br />
这也是所有的ORM产品共同具有的问题。幸运的是，Hibernate为我们暴露了Cache的清除方法，这给我们 <br />
<br />
提供了一个手动保证数据有效性的机会！！ <br />
<br />
一级缓存，二级缓存都有相应的清除方法。 <br />
<br />
<br />
<br />
其中二级缓存提供的清除方法为： <br />
<br />
按对象class清空缓存 <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 按对象class和对象的主键id清空缓存 <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 清空对象的集合中的缓存数据等。 <br />
<br />
&nbsp;&nbsp;&nbsp; <br />
<br />
1.3.2.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 适合使用的情况 <br />
并非所有的情况都适合于使用二级缓存，需要根据具体情况来决定。同时可以针对某一个持久化对象配 <br />
<br />
置其具体的缓存策略。 <br />
<br />
<br />
<br />
适合于使用二级缓存的情况： <br />
<br />
1、数据不会被第三方修改； <br />
<br />
<br />
<br />
一般情况下，会被hibernate以外修改的数据最好不要配置二级缓存，以免引起不一致的数据。但是如果 <br />
<br />
此数据因为性能的原因需要被缓存，同时又有可能被第3方比如SQL修改，也可以为其配置二级缓存。只 <br />
<br />
是此时需要在sql执行修改后手动调用cache的清除方法。以保证数据的一致性 <br />
<br />
<br />
<br />
&nbsp; 2、数据大小在可接收范围之内； <br />
<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 如果数据表数据量特别巨大，此时不适合于二级缓存。原因是缓存的数据量过大可能会引起内存资 <br />
<br />
源紧张，反而降低性能。 <br />
<br />
<br />
<br />
如果数据表数据量特别巨大，但是经常使用的往往只是较新的那部分数据。此时，也可为其配置二级缓 <br />
<br />
存。但是必须单独配置其持久化类的缓存策略，比如最大缓存数、缓存过期时间等，将这些参数降低至 <br />
<br />
一个合理的范围（太高会引起内存资源紧张，太低了缓存的意义不大）。 <br />
<br />
<br />
<br />
&nbsp; 3、数据更新频率低； <br />
<br />
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp; 对于数据更新频率过高的数据，频繁同步缓存中数据的代价可能和 查询缓存中的数据从中获得的 <br />
<br />
好处相当，坏处益处相抵消。此时缓存的意义也不大。 <br />
<br />
<br />
<br />
<br />
<br />
&nbsp; 4、非关键数据（不是财务数据等） <br />
<br />
<br />
<br />
&nbsp; 财务数据等是非常重要的数据，绝对不允许出现或使用无效的数据，所以此时为了安全起见最好不要 <br />
<br />
使用二级缓存。 <br />
<br />
&nbsp; 因为此时 &#8220;正确性&#8221;的重要性远远大于 &#8220;高性能&#8221;的重要性。 <br />
<br />
<br />
<br />
2.&nbsp;&nbsp;&nbsp;&nbsp; 目前系统中使用hibernate缓存的建议 <br />
1.4.&nbsp;&nbsp; 目前情况 <br />
一般系统中有三种情况会绕开hibernate执行数据库操作： <br />
<br />
1、多个应用系统同时访问一个数据库 <br />
<br />
&nbsp;&nbsp; 此种情况使用hibernate二级缓存会不可避免的造成数据不一致的问题， <br />
<br />
&nbsp;&nbsp; 此时要进行详细的设计。比如在设计上避免对同一数据表的同时的写入操作， <br />
<br />
&nbsp;&nbsp; 使用数据库各种级别的锁定机制等。 <br />
<br />
<br />
<br />
2、动态表相关 <br />
<br />
&nbsp;&nbsp; 所谓&#8220;动态表&#8221;是指在系统运行时根据用户的操作系统自动建立的数据表。 <br />
<br />
&nbsp;&nbsp; 比如&#8220;自定义表单&#8221;等属于用户自定义扩展开发性质的功能模块，因为此时数据表是运行时建立的， <br />
<br />
所以不能进行hibernate的映射。因此对它的操作只能是绕开hibernate的直接数据库JDBC操作。 <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如果此时动态表中的数据没有设计缓存，就不存在数据不一致的问题。 <br />
<br />
 <img src ="http://www.blogjava.net/lanxin1020/aggbug/264983.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lanxin1020/" target="_blank">lanxin1020</a> 2009-04-11 10:24 <a href="http://www.blogjava.net/lanxin1020/archive/2009/04/11/264983.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate 缓存机制(转)</title><link>http://www.blogjava.net/lanxin1020/archive/2009/04/11/264973.html</link><dc:creator>lanxin1020</dc:creator><author>lanxin1020</author><pubDate>Sat, 11 Apr 2009 02:18:00 GMT</pubDate><guid>http://www.blogjava.net/lanxin1020/archive/2009/04/11/264973.html</guid><wfw:comment>http://www.blogjava.net/lanxin1020/comments/264973.html</wfw:comment><comments>http://www.blogjava.net/lanxin1020/archive/2009/04/11/264973.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lanxin1020/comments/commentRss/264973.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lanxin1020/services/trackbacks/264973.html</trackback:ping><description><![CDATA[<div class="blog_content">缓存是介于应用程序和物理数据源之间，其作用是为了降低应用程序对物理数据源访问的频次，从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制，应用程序在运行时从缓存读写数据，在特定的时刻或事件会同步缓存和物理数据源的数据。 <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 />
　　事务型并发访问策略是事务隔离级别最高，只读型的隔离级别最低。事务隔离级别越高，并发性能就越低。 </div>
 <img src ="http://www.blogjava.net/lanxin1020/aggbug/264973.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lanxin1020/" target="_blank">lanxin1020</a> 2009-04-11 10:18 <a href="http://www.blogjava.net/lanxin1020/archive/2009/04/11/264973.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate 体系结构与工作原理(转)</title><link>http://www.blogjava.net/lanxin1020/archive/2009/04/09/264745.html</link><dc:creator>lanxin1020</dc:creator><author>lanxin1020</author><pubDate>Thu, 09 Apr 2009 15:54:00 GMT</pubDate><guid>http://www.blogjava.net/lanxin1020/archive/2009/04/09/264745.html</guid><wfw:comment>http://www.blogjava.net/lanxin1020/comments/264745.html</wfw:comment><comments>http://www.blogjava.net/lanxin1020/archive/2009/04/09/264745.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lanxin1020/comments/commentRss/264745.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lanxin1020/services/trackbacks/264745.html</trackback:ping><description><![CDATA[<div>1.Hibernate 的初始化.<br />
读取Hibernate 的配置信息-〉创建Session Factory<br />
1)创建Configeration类的实例。<br />
它的构造方法：将配置信息(Hibernate config.xml)读入到内存。<br />
一个Configeration 实例代表Hibernate 所有Java类到Sql数据库映射的集合。<br />
2)创建SessionFactory实例<br />
把Configeration 对象中的所有配置信息拷贝到SessionFactory的缓存中。<br />
SessionFactory的实例代表一个数据库存储员源，创建后不再与Configeration 对象关联。<br />
缓存(cache):指Java对象的属性(通常是一些集合类型的属性－－占用内存空间。<br />
&nbsp;&nbsp;&nbsp;&nbsp; SessionFactory的缓存中：Hibernate 配置信息。OR映射元数据。<br />
缓存－大：重量级对象 小：轻量级对象<br />
3)调用SessionFactory创建Session的方法<br />
1】用户自行提供JDBC连接。<br />
&nbsp;&nbsp; Connection con=dataSource.getConnection();<br />
&nbsp;&nbsp; Session s=sessionFactory.openSession(con);<br />
2】让SessionFactory提供连接<br />
&nbsp;&nbsp; Session s=sessionFactory.openSession();<br />
4)通过Session 接口提供的各种方法来操纵数据库访问。
<p>Hibernate 的缓存体系<br />
一级缓存：<br />
Session 有一个内置的缓存，其中存放了被当前工作单元加载的对象。<br />
每个Session 都有自己独立的缓存，且只能被当前工作单元访问。<br />
二级缓存：<br />
SessionFactory的外置的可插拔的缓存插件。其中的数据可被多个Session共享访问。<br />
SessionFactory的内置缓存：存放了映射元数据，预定义的Sql语句。</p>
<p>Hibernate 中Java对象的状态<br />
1.临时状态 (transient)<br />
特征：<br />
&nbsp;&nbsp; 1】不处于Session 缓存中<br />
&nbsp;&nbsp; 2】数据库中没有对象记录<br />
Java如何进入临时状态<br />
&nbsp;&nbsp; 1】通过new语句刚创建一个对象时<br />
&nbsp;&nbsp; 2】当调用Session 的delete()方法，从Session 缓存中删除一个对象时。</p>
<p>2.持久化状态(persisted)<br />
特征：<br />
&nbsp;&nbsp; 1】处于Session 缓存中<br />
&nbsp;&nbsp; 2】持久化对象数据库中设有对象记录<br />
&nbsp;&nbsp; 3】Session 在特定时刻会保持二者同步<br />
Java如何进入持久化状态<br />
&nbsp;&nbsp; 1】Session 的save()把临时－》持久化状态<br />
&nbsp;&nbsp; 2】Session 的load(),get()方法返回的对象<br />
&nbsp;&nbsp; 3】Session 的find()返回的list集合中存放的对象<br />
&nbsp;&nbsp; 4】Session 的update(),saveOrupdate()使游离－》持久化<br />
3.游离状态(detached)<br />
特征：<br />
&nbsp;&nbsp; 1】不再位于Session 缓存中<br />
&nbsp;&nbsp; 2】游离对象由持久化状态转变而来，数据库中可能还有对应记录。<br />
Java如何进入持久化状态－》游离状态<br />
&nbsp;&nbsp; 1】Session 的close()方法<br />
&nbsp;&nbsp; 2】Session 的evict()方法，从缓存中删除一个对象。提高性能。少用。</p>
</div>
 <img src ="http://www.blogjava.net/lanxin1020/aggbug/264745.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lanxin1020/" target="_blank">lanxin1020</a> 2009-04-09 23:54 <a href="http://www.blogjava.net/lanxin1020/archive/2009/04/09/264745.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate 的原理与配置(转)</title><link>http://www.blogjava.net/lanxin1020/archive/2009/04/09/264744.html</link><dc:creator>lanxin1020</dc:creator><author>lanxin1020</author><pubDate>Thu, 09 Apr 2009 15:50:00 GMT</pubDate><guid>http://www.blogjava.net/lanxin1020/archive/2009/04/09/264744.html</guid><wfw:comment>http://www.blogjava.net/lanxin1020/comments/264744.html</wfw:comment><comments>http://www.blogjava.net/lanxin1020/archive/2009/04/09/264744.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lanxin1020/comments/commentRss/264744.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lanxin1020/services/trackbacks/264744.html</trackback:ping><description><![CDATA[也许你听说过Hibernate的大名，但可能一直不了解它，也许你一直渴望使用它进行开发，那么本文正是你所需要的！在本文中，我向大家重点介绍Hibernate的核心API调用库，并讲解一下它的基本配置。 <br />
<br />
　　看完本文后，我相信你对什么是ORM（对像/关系映射）以及它的优点会有一个深刻的认识，我们先通过一个简单的例子开始来展现它的威力。 <br />
<br />
　　正如一些传统的经典计算机文章大都会通过一个&#8220;hello,world&#8221;的例子开始讲解一样，我们也不例外，我们也将从一个相对简单的例子来阐述Hibernate的开发方法，但如果要真正阐述Hibernate的一些重要思想，仅仅靠在屏幕上打印一些字符是远远不够的，在我们的示例程序中，我们将创建一些对象，并将其保存在数据库中，然后对它们进行更新和查询。 <br />
<br />
<strong>　　阅读导航</strong>
<p>　　&#8220;Hello World&#8221;&#8220;Hello world&#8221;示例程序让您对Hibernate有一个简单的认识。 <br />
　　理解Hibernate的架构介绍Hibernate接口的主要功能。 <br />
　　核心接口Hibernate有5个核心接口，通过这几个接口开发人员可以存储和获得持久对象，并且能够进行事务控制 <br />
　　一个重要的术语：TypeType是Hibernate发明者发明的一个术语，它在整个构架中是一个非常基础、有着强大功能的元素，一个Type对象能将一个Java类型映射到数据库中一个表的字段中去。 <br />
　　策略接口Hibernate与某些其它开源软件不同的还有一点――高度的可扩展性，这通过它的内置策略机制来实现。 <br />
　　基础配置Hibernate可以配置成可在任何Java环境中运行，一般说来，它通常被用在2－3层的C/S模式的项目中，并被部署在服务端。 <br />
　　创建一个SessionFactory对象要创建一个SessionFactory对象，必须在Hibernate初始化时创建一个Configuration类的实例，并将已写好的映射文件交由它处理。 <br />
<br />
<strong>　　&#8220;Hello World&#8221; <br />
</strong><br />
　　Hibernate应用程序定义了一些持久类，并且定义了这些类与数据库表格的映射关系。在我们这个&#8220;Hello world&#8221;示例程序中包含了一个类和一个映射文件。让我们看看这个简单的持久类包含有一些什么？映射文件是怎样定义的？另外，我们该怎样用Hibernate来操作这个持久类。 <br />
<br />
　　我们这个简单示例程序的目的是将一些持久类存储在数据库中，然后从数据库取出来，并将其信息正文显示给用户。其中Message正是一个简单的持久类：，它包含我们要显示的信息，其源代码如下： <br />
<br />
　　列表1　Message.Java　一个简单的持久类 <br />
<br />
　　package hello; <br />
　　public class Message { <br />
　　private Long id; <br />
　　private String text; <br />
　　private Message nextMessage; <br />
　　private Message() {} <br />
　　public Message(String text) { <br />
　　this.text = text; <br />
　　} <br />
　　public Long getId() { <br />
　　return id; <br />
　　} <br />
　　private void setId(Long id) { <br />
　　this.id = id; <br />
　　} <br />
　　public String getText() { <br />
　　return text; <br />
　　} <br />
　　public void setText(String text) { <br />
　　this.text = text; <br />
　　} <br />
　　public Message getNextMessage() { <br />
　　return nextMessage; <br />
　　} <br />
　　public void setNextMessage(Message nextMessage) { <br />
　　this.nextMessage = nextMessage; <br />
　　} <br />
　　} <br />
<br />
　　Message类有三个属性：Message的id 、消息正文、以及一个指向下一条消息的指针。其中id属性让我们的应用程序能够唯一的识别这条消息，通常它等同于数据库中的主键，如果多个Message类的实例对象拥有相同的id，那它们代表数据库某个表的同一个记录。在这里我们选择了长整型作为我们的id值，但这不是必需的。Hibernate允许我们使用任意的类型来作为对象的id值，在后面我们会对此作详细描述。 <br />
<br />
　　你可能注意到Message类的代码类似于JavaBean的代码风格，并且它有一个没有参数的构造函数，在我们以后的代码中我将继续使用这种风格来编写持久类的代码。 <br />
<br />
　　Hibernate会自动管理Message类的实例，并通过内部机制使其持久化，但实际上Message对象并没有实现任何关于Hibernate的类或接口，因此我们也可以将它作为一个普通的Java类来使用： <br />
<br />
　　Message message = new Message("Hello World"); <br />
　　System.out.println( message.getText() ); <br />
<br />
　　以上这段代码正是我们所期望的结果：它打印&#8220;hello world&#8221;到屏幕上。但这并不是我们的最终目标；实际上Hibernate与诸如EJB容器这样的环境在持久层实现的方式上有很大的不同。我们的持久类(Message类)可以用在与容器无关的环境中，不像EJB必须要有EJB容器才能执行。为了能更清楚地表现这点，以下代码将我们的一个新消息保存到数据库中去： <br />
<br />
　　Session session = getSessionFactory().openSession(); <br />
　　Transaction tx = session.beginTransaction(); <br />
　　Message message = new Message("Hello World"); <br />
　　session.save(message); <br />
　　tx.commit(); <br />
　　session.close(); <br />
<br />
　　以上这段代码调用了Hibernate的Session和Transaction接口（关于getSessionFactory()方法我们将会马上提到）。它相当于我们执行了以下SQL语句： <br />
<br />
　　insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID) <br />
　　values (1, 'Hello World', null) <br />
<br />
　　在以上的SQL语句中，MESSAGE_ID字段到底被初始化成了什么值呢？由于我们并没有在先前的代码中为message对象的id属性赋与初始值，那它是否为null呢？实际上Hibernate对id属性作了特殊处理：由于它是一个对象的唯一标识，因此当我们进行save()调用时，Hibernate会为它自动赋予一个唯一的值（我们将在后面内容中讲述它是如何生成这个值的）。 <br />
<br />
　　我们假设你已经在数据库中创建了一个名为MESSAGE的表，那么既然前面这段代码让我们将Message对象存入了数据库中，那么现在我们就要将它们一一取出来。下面这段代码将按照字母顺序，将数据库中的所有Message对象取出来，并将它们的消息正文打印到屏幕上： <br />
<br />
　　Session newSession = getSessionFactory().openSession(); <br />
　　Transaction newTransaction = newSession.beginTransaction(); <br />
　　List messages =newSession.find("from Message as m order by m.text asc"); <br />
　　System.out.println( messages.size() + " message(s) found:" ); <br />
　　for ( Iterator iter = messages.iterator(); iter.hasNext(); ) { <br />
　　Message message = (Message) iter.next(); <br />
　　System.out.println( message.getText() ); <br />
　　} <br />
　　newTransaction.commit(); <br />
　　newSession.close(); <br />
<br />
　　在以上这段代码中，你可能被find()方法的这个参数困扰着："from Message as m order by m.text asc"，其实它是Hibernate自己定义的查询语言，全称叫Hibernate Query Language(HQL)。通俗地讲HQL与SQL的关系差不多就是方言与普通话之间的关系，咋一看，你会觉得它有点类似于SQL语句。其实在find()调用时，Hibernate会将这段HQL语言翻译成如下的SQL语句： <br />
<br />
　　select m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID <br />
　　from MESSAGES m <br />
　　order by m.MESSAGE_TEXT asc <br />
<br />
　　以下就是运行结果： <br />
<br />
　　1 message(s) found: <br />
　　Hello World <br />
<br />
　　如果你以前没有ORM（对象－关系映射）的开发经验，那你可能想在代码的某个地方去寻找这段SQL语句，但在Hibernate中你可能会失望：它根本不存在！所有就SQL语句都是Hibernate动态生成的。 <br />
<br />
　　也许你会觉得还缺点什么，对！仅凭以上代码Hibernate是无法将我们的Message类持久化的。我们还需要一些更多的信息，这就是映射定义表！这个表在Hibernate中是以XML格式来体现的，它定义了Message类的属性是怎样与数据库中的MESSAGES表的字段进行一一对应的，列表2是这个示例程序的映射配置文件清单： <br />
<br />
　　列表2：示例程序的对象－关系映射表 <br />
<br />
　　＜?xml version="1.0"?＞ <br />
　　＜!DOCTYPE hibernate-mapping PUBLIC <br />
　　"-//Hibernate/Hibernate Mapping DTD//EN" <br />
　　"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"＞ <br />
　　＜hibernate-mapping＞ <br />
　　＜class name="hello.Message" table="MESSAGES"＞ <br />
　　＜id name="id" column="MESSAGE_ID"＞ <br />
　　＜generator class="increment"/＞ <br />
　　＜/id＞ <br />
　　＜property name="text" column="MESSAGE_TEXT"/＞ <br />
　　＜many-to-one name="nextMessage" cascade="all" column="NEXT_MESSAGE_ID"/＞ <br />
　　＜/class＞ <br />
　　＜/hibernate-mapping＞ <br />
<br />
　　以上这个文档告诉Hibernate怎样将Message类映射到MESSAGES表中，其中Message类的id属性与表的MESSAGE_ID字段对应，text属性与表的MESSAGE_TEXT字段对应，nextMessage属性是一个多对一的关系，它与表中的NEXT_MESSAGE_ID相对应。 <br />
<br />
　　相对于有些开源项目来说，Hibernate的配置文件其实是很容易理解的。你可以轻松地修改与维护它。只要你定义好了持久类与数据库中表字段的对应关系就行了，Hibernate会自动帮你生成SQL语句来对Message对象进行插入、更新、删除、查找工作，你可以不写一句SQL语句，甚至不需要懂得SQL语言！ <br />
<br />
　　现在让我们做一个新的试验，我们先取出第一个Message对象，然后修改它的消息正文，最后我们再生成一个新的Message对象，并将它作为第一个Message对象的下一条消息，其代码如下： <br />
<br />
　　列表3　更新一条消息 <br />
<br />
　　Session session = getSessionFactory().openSession(); <br />
　　Transaction tx = session.beginTransaction(); <br />
　　// 1 is the generated id of the first message <br />
　　Message message =(Message) session.load( Message.class, new Long(1) ); <br />
　　message.setText("Greetings Earthling"); <br />
　　Message nextMessage = new Message("Take me to your leader (please)"); <br />
　　message.setNextMessage( nextMessage ); <br />
　　tx.commit(); <br />
　　session.close(); <br />
<br />
　　以上这段代码在调用时，Hibernate内部自动生成如下的SQL语句： <br />
<br />
　　select m.MESSAGE_ID, m.MESSAGE_TEXT, m.NEXT_MESSAGE_ID <br />
　　from MESSAGES m <br />
　　where m.MESSAGE_ID = 1 <br />
<br />
　　insert into MESSAGES (MESSAGE_ID, MESSAGE_TEXT, NEXT_MESSAGE_ID) <br />
　　values (2, 'Take me to your leader (please)', null) <br />
<br />
　　update MESSAGES <br />
　　set MESSAGE_TEXT = 'Greetings Earthling', NEXT_MESSAGE_ID = 2 <br />
　　where MESSAGE_ID = 1 <br />
<br />
　　当第一个Message对象的text属性和nextMessage被程序修改时，请注意Hibernate是如何检测到这种变化，并如何在数据库中自动对它更新的。这实际上是Hibernate的一个很有价值的特色，我们把它称为&#8220;自动脏数据检测&#8221;，Hibernate的这个特色使得当我们修改一个持久对象的属性后，不必显式地通知Hibernate去将它在数据库中进行更新。同样的，当第一个Message对象调用setNextMessage()方法将第二个Message对象作为它的下一条消息的引用时，第二条消息会无需调用save()方法，便可以自动地保存在数据库中。这种特色被称为&#8220;级联保存&#8221;，它也免去了我们显式地对第二个Message对象调用save()方法之苦。 <br />
<br />
　　如果我们再运行先前的那段将数据库中所有的Message对象都打印出来的代码，那它的运行结果如下： <br />
<br />
　　2 message(s) found: <br />
　　Greetings Earthling <br />
　　Take me to your leader (please) <br />
<br />
<br />
　　&#8220;Hello world&#8221;示例程序现在介绍完毕。我们总算对Hibernate有了一个简单的认识，下面我们将回过头来，对Hibernate的主要API调用作一下简要的介绍： <br />
　　 <br />
<br />
　<strong>　理解Hibernate的架构</strong> <br />
<br />
　　当你想用Hibernate开发自己的基于持久层的应用时，第一件事情应当是熟悉它的编程接口。Hibernate的API接口设计得尽量简洁明了，以方便开发人员。然而实际上由于ORM的复杂性，它的API一般都不可能设计得很简单。但是别担心，你没有必要一下子了解所有的Hibernate的API接口。<br />
<br />
　　我们将应用层放在了持久层的上部，实际上在传统的项目中，应用层充当着持久层的一个客户端角色。但对于一些简单的项目来说，应用层和持久层并没有区分得那么清楚，这也没什么，在这种情况下你可以将应用层和持久层合并成了一层。 <br />
<br />
　　<strong>Hibernate的接口大致可以分为以下几种类型：</strong> <br />
<br />
　　&#183; 一些被用户的应用程序调用的，用来完成基本的创建、读取、更新、删除操作以及查询操作的接口。这些接口是Hibernate实现用户程序的商业逻辑的主要接口，它们包括Session、Transaction和Query。 <br />
<br />
　　&#183; Hibernate用来读取诸如映射表这类配置文件的接口，典型的代表有Configuration类。 <br />
<br />
　　&#183; 回调(Callback)接口。它允许应用程序能对一些事件的发生作出相应的操作，例如Interceptor、Lifecycle和Validatable都是这一类接口。 <br />
<br />
　　&#183; 一些可以用来扩展Hibernate的映射机制的接口，例如UserType、CompositeUserType和IdentifierGenerator。这些接口可由用户程序来实现（如果有必要）。 <br />
<br />
　　Hibernate使用了J2EE架构中的如下技术：JDBC、JTA、JNDI。其中JDBC是一个支持关系数据库操作的一个基础层；它与JNDI和JTA一起结合，使得Hibernate可以方便地集成到J2EE应用服务器中去。 <br />
<br />
　　在这里，我们不会详细地去讨论Hibernate API接口中的所有方法，我们只简要讲一下每个主要接口的功能，如果你想了解得更多的话，你可以在Hibernate的源码包中的net.sf.hibernate子包中去查看这些接口的源代码。下面我们依次讲一下所有的主要接口： <br />
<br />
　<strong>　</strong>核心接口 <br />
<br />
　　以下5个核心接口几乎在任何实际开发中都会用到。通过这些接口，你不仅可以存储和获得持久对象，并且能够进行事务控制。 <br />
<br />
　　Session接口 <br />
<br />
　　Session接口对于Hibernate 开发人员来说是一个最重要的接口。然而在Hibernate中，实例化的Session是一个轻量级的类，创建和销毁它都不会占用很多资源。这在实际项目中确实很重要，因为在客户程序中，可能会不断地创建以及销毁Session对象，如果Session的开销太大，会给系统带来不良影响。但值得注意的是Session对象是非线程安全的，因此在你的设计中，最好是一个线程只创建一个Session对象。 <br />
<br />
　　在Hibernate的设计者的头脑中，他们将session看作介于数据连接与事务管理一种中间接口。我们可以将session想象成一个持久对象的缓冲区，Hibernate能检测到这些持久对象的改变，并及时刷新数据库。我们有时也称Session是一个持久层管理器，因为它包含这一些持久层相关的操作，诸如存储持久对象至数据库，以及从数据库从获得它们。请注意，Hibernate 的session不同于JSP应用中的HttpSession。当我们使用session这个术语时，我们指的是Hibernate中的session，而我们以后会将HttpSesion对象称为用户session。 <br />
<br />
　　SessionFactory 接口 <br />
<br />
　　这里用到了一个设计模式――工厂模式，用户程序从工厂类SessionFactory中取得Session的实例。 <br />
<br />
　　令你感到奇怪的是SessionFactory并不是轻量级的！实际上它的设计者的意图是让它能在整个应用中共享。典型地来说，一个项目通常只需要一个SessionFactory就够了，但是当你的项目要操作多个数据库时，那你必须为每个数据库指定一个SessionFactory。 <br />
　　SessionFactory在Hibernate中实际起到了一个缓冲区的作用，它缓冲了Hibernate自动生成的SQL语句和一些其它的映射数据，还缓冲了一些将来有可能重复利用的数据。 <br />
<br />
　　Configuration 接口 <br />
<br />
　　Configuration接口的作用是对Hibernate进行配置，以及对它进行启动。在Hibernate的启动过程中，Configuration类的实例首先定位映射文档的位置，读取这些配置，然后创建一个SessionFactory对象。 <br />
<br />
　　虽然Configuration接口在整个Hibernate项目中只扮演着一个很小的角色，但它是启动hibernate时你所遇到的每一个对象。 <br />
<br />
　　Transaction 接口 <br />
<br />
　　Transaction接口是一个可选的API，你可以选择不使用这个接口，取而代之的是Hibernate的设计者自己写的底层事务处理代码。 Transaction接口是对实际事务实现的一个抽象，这些实现包括JDBC的事务、JTA中的UserTransaction、甚至可以是CORBA事务。之所以这样设计是能让开发者能够使用一个统一事务的操作界面，使得自己的项目可以在不同的环境和容器之间方便地移值。 <br />
<br />
　　Query和Criteria接口 <br />
<br />
　　Query接口让你方便地对数据库及持久对象进行查询，它可以有两种表达方式：HQL语言或本地数据库的SQL语句。Query经常被用来绑定查询参数、限制查询记录数量，并最终执行查询操作。 <br />
<br />
　　Criteria接口与Query接口非常类似，它允许你创建并执行面向对象的标准化查询。 <br />
<br />
　　值得注意的是Query接口也是轻量级的，它不能在Session之外使用。 <br />
<br />
　　Callback 接口 <br />
<br />
　　当一些有用的事件发生时――例如持久对象的载入、存储、删除时，Callback接口会通知Hibernate去接收一个通知消息。一般而言，Callback接口在用户程序中并不是必须的，但你要在你的项目中创建审计日志时，你可能会用到它。 <br />
<br />
　　<strong> 一个重要的术语：Type <br />
</strong><br />
　　Hibernate的设计者们发明了一个术语：Type，它在整个构架中是一个非常基础、有着强大功能的元素。一个Type对象能将一个Java类型映射到数据库中一个表的字段中去（实际上，它可以映射到表的多个字段中去）。持久类的所有属性都对应一个type。这种设计思想使用Hibernate有着高度的灵活性和扩展性。 <br />
<br />
　　Hibernate内置很多type类型，几乎包括所有的Java基本类型，例如Java.util.Currency、Java.util.calendar、byte[]和Java.io.Serializable。 <br />
<br />
　　不仅如此，Hibernate还支持用户自定义的type，通过实现接口UserType和接口CompositeUserType，你可以加入自己的type。你可以利用这种特色让你的项目中使用自定义的诸如Address、Name这样的type，这样你就可以获得更大的便利，让你的代码更优雅。自定义type在Hibernate中是一项核心特色，它的设计者鼓励你多多使用它来创建一个灵活、优雅的项目！ <br />
<br />
　　策略接口 <br />
<br />
　　Hibernate与某些其它开源软件不同的还有一点――高度的可扩展性，这通过它的内置策略机制来实现。当你感觉到Hibernate的某些功能不足，或者有某些缺陷时，你可以开发一个自己的策略来替换它，而你所要做的仅仅只是继承它的某个策略接口，然后实现你的新策略就可以了，以下是它的策略接口： <br />
<br />
　　&#183; 主键的生成 (IdentifierGenerator 接口) <br />
<br />
　　&#183; 本地SQL语言支持 (Dialect 抽象类) <br />
<br />
　　&#183; 缓冲机制 (Cache 和CacheProvider 接口) <br />
<br />
　　&#183; JDBC 连接管理 (ConnectionProvider接口) <br />
<br />
　　&#183; 事务管理 (TransactionFactory, Transaction, 和 TransactionManagerLookup 接口) <br />
<br />
　　&#183; ORM 策略 (ClassPersister 接口) <br />
<br />
　　&#183; 属性访问策略 (PropertyAccessor 接口) <br />
<br />
　　&#183; 代理对象的创建 (ProxyFactory接口) <br />
<br />
　　Hibernate为以上所列的机制分别创建了一个缺省的实现，因此如果你只是要增强它的某个策略的功能的话，只需简单地继承这个类就可以了，没有必要从头开始写代码。 <br />
<br />
　　以上就是Hibernate的一些核心接口，但当我们真正开始用它进行开发时，你的脑海里可能总会有一个疑问：我是通过什么方式，并从哪里取得Session的呢？以下我们就解答这个问题。 <br />
<br />
　　基础配置 <br />
<br />
　　现在回顾一下我们先前的内容：我们写出了一个示例程序，并简要地讲解了Hibernate的一些核心类。但要真正使你的项目运行起来，还有一件事必须要做：配置。Hibernate可以配置成可在任何Java环境中运行，一般说来，它通常被用在2－3层的C/S模式的项目中，并被部署在服务端。在这种项目中，Web浏览器、或Java GUI程序充当者客户端。尽管我们的焦点主要是集中在多层web应用，但实际上在一些基于命令行的应用中也可以使用Hibernate。并且，对Hibernate的配置在不同的环境下都会不同，Hibernate运行在两种环境下：可管理环境和不可管理环境 <br />
<br />
　　&#183; 可管理环境――这种环境可管理如下资源：池资源管理，诸如数据库连接池和，还有事务管理、安全定义。一些典型的J2EE服务器（JBoss、Weblogic、WebSphere）已经实现了这些。 <br />
<br />
　　&#183; 不可管理环境――只是提供了一些基本的功能，诸如像Jetty或Tomcat这样的servlet容器环境。一个普通的Java桌面应用或命令行程序也可以认为是处于这种环境下。这种环境不能提供自动事务处理、资源管理或安全管理，这些都必须由应用程序自己来定义。 <br />
<br />
　　Hibernate的设计者们将这两种环境设计了一个统一的抽象界面，因此对于开发者来说只有一种环境：可管理环境。如果实际项目是建立在诸如Tomcat这类不可管理的环境中时，那Hibernate将会使用它自己的事务处理代码和JDBC连接池，使其变为一个可管理环境。 <br />
　　对于可管理的环境而言，Hibernate会将自己集成在这种环境中。对于开发者而言，你所要做的工作非常简单：只需从一个Configuration类中创建一个SessionFactory类就可以了。 <br />
　　 创建一个SessionFactory对象 <br />
<br />
　　为了能创建一个SessionFactory对象，你必须在Hibernate初始化时创建一个Configuration类的实例，并将已写好的映射文件交由它处理。这样，Configuration对象就可以创建一个SessionFactory对象，当SessionFactory对象创建成功后，Configuration对象就没有用了，你可以简单地抛弃它。如下是示例代码： <br />
<br />
　　Configuration cfg = new Configuration(); <br />
　　cfg.addResource("hello/Message.hbm.xml"); <br />
　　cfg.setProperties( System.getProperties() ); <br />
　　SessionFactory sessions = cfg.buildSessionFactory(); <br />
<br />
　　在以上代码中，Message.hb.xml这个映射文件的位置比较特殊，它与当前的classpath相关。例如classpath包含当前目录，那在上述代码中的Message.hbm.xml映射文件就可以保存在当前目录下的hello目录中。 <br />
<br />
　　作为一种约定，Hibernate的映射文件默认以.htm.xml作为其扩展名。另一个约定是坚持为每一个持久类写一个配置文件，想一想如果你将所有持久类的映射写入一个单独的配置文件中的话，那这个配置文件肯定非常庞大，不易维护。但这里又出现了一个新问题：如果为每个类写一个配置文件的话，这么多的配置文件应该存放在哪里呢？ <br />
<br />
　　Hibernate推荐你将每个映射文件保存在与持久类相同的目录下，并且与持久类同名。例如我们第一个示例程序中的Message持久类放在hello目录下，那你必须在这个目录下存放名为Message.hbm.xml的映射文件。这样一个持久类都有自己的一个映射文件，避免了出现像struts项目中的&#8220;struts-config.xml地狱&#8221;的情况。如果你不遵循这种规定，那你必须手动地用addResource()方法将一个个的映射文件载入；但你如果遵循这种规定，那你可以方便地用addClass()方法同时将持久类和它的映射文件载入，以下是体现这种便利性的示例代码： <br />
<br />
　　SessionFactory sessions = new Configuration() <br />
　　.addClass(org.hibernate.auction.model.Item.class) <br />
　　.addClass(org.hibernate.auction.model.Category.class) <br />
　　.addClass(org.hibernate.auction.model.Bid.class) <br />
　　.setProperties( System.getProperties() ) <br />
　　.buildSessionFactory(); <br />
<br />
　　当然，Hibernate的映射文件还有很多其它的配置选项，比如数据库连接的设定，或是能够改变Hibernate运行时行为的一些设定。所有的设置可能是非常庞杂的，足以让你喘不过气来，但是不必担心，因为Hibernate为绝大多数值都设定了一个合理缺省值，你只需要修改这些配置文件中的极小一部分值。 <br />
<br />
　　你可以通过以下几种方式来修改Hibernate的系统配置参数： <br />
<br />
　　&#183; 将一个Java.util.Properties实例作为参数传给Configuration类的setProperties()方法。 <br />
<br />
　　&#183; 在Hibernate启动时用Java &#8211;Dproperty=value的方式设置值。 <br />
<br />
　　&#183; 在classpath可以找到的路径下创建一个名为hibernate.properties的配置文件。 <br />
<br />
　　&#183; 在classpath可以找到的路径下创建一个名为hibernate.cfg.xml的文件，并在其＜property＞标签中定义属性值。 <br />
<br />
　　以上就是对Hibernate的一个大致介绍，如果你想知道得更多，那本文还是远远不够的，我将陆续推出更多关于Hibernate的资料。但有一点是毫无疑问的：它的确是一个非常优秀的持久层解决方案！</p>
<br clear="all" />
 <img src ="http://www.blogjava.net/lanxin1020/aggbug/264744.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lanxin1020/" target="_blank">lanxin1020</a> 2009-04-09 23:50 <a href="http://www.blogjava.net/lanxin1020/archive/2009/04/09/264744.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate实体对象的生命周期（转）</title><link>http://www.blogjava.net/lanxin1020/archive/2009/04/08/264425.html</link><dc:creator>lanxin1020</dc:creator><author>lanxin1020</author><pubDate>Wed, 08 Apr 2009 04:02:00 GMT</pubDate><guid>http://www.blogjava.net/lanxin1020/archive/2009/04/08/264425.html</guid><wfw:comment>http://www.blogjava.net/lanxin1020/comments/264425.html</wfw:comment><comments>http://www.blogjava.net/lanxin1020/archive/2009/04/08/264425.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lanxin1020/comments/commentRss/264425.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lanxin1020/services/trackbacks/264425.html</trackback:ping><description><![CDATA[<h3 title="随笔"><a href="/blog/269076">Hibernate实体对象的生命周期</a></h3>
<strong>关键字: hibernate学习笔记</strong>
<div class="blog_content">在用Hibernate的时候，时不时会因为没有处理好实体对象的状态而犯一些莫名其妙的异常，在这里对实体对象的各种状态整理一下，希望能有所帮助。 <br />
<br />
Hibernate实体对象，即指Hibernate O/R影射关系中的域对象 即O/R中的"O"。在Hibrenate实体对象的生命周期中存在着三中状态，即： <br />
1：自由状态（Transient）。 <br />
2：持久状态（Persistent）。 <br />
3：游离状态（Detached）。 <br />
<br />
<span style="color: red"><strong>1：自由状态（Transient）</strong></span> <br />
<span style="color: brown">自由状态（Transient）</span>,是指实体对象在内存中自由存在，他与数据库的记录无关。如： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div>
</div>
<ol class="dp-j">
    <li><span><span>TUser&nbsp;user&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;TUser(); &nbsp;&nbsp;</span></span>
    <li><span>user.setName(</span><span class="string">"MyName"</span><span>);&nbsp;&nbsp;</span></span> </li>
</ol>
</div>
<pre style="display: none" class="java" name="code">TUser user = new TUser();
user.setName("MyName");
</pre>
<br />
这里的user对象只是一个非常普通的java对象，与数据库中的记录没有任何关系。 <br />
<br />
<span style="color: red"><strong>2：持久状态（Persistent）</strong></span> <br />
<span style="color: brown">持久状态（Persistent）</span>,即实体对象处于Hibernate框架的管理状态，实体对象被纳入Hibernate的实体容器中管理。处于<span style="color: brown">持久状态</span>的对象，其更变将由Hibernate固化到数据库中。如： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div>
</div>
<ol class="dp-j">
    <li><span><span class="comment">//创建两个处于自由状态的实体对象。 </span><span>&nbsp;&nbsp;</span></span>
    <li><span>TUser&nbsp;user_1&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;TUser(); &nbsp;&nbsp;</span></span>
    <li><span>TUser&nbsp;user_2&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;TUser(); &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>user_1.setName(</span><span class="string">"Name_1"</span><span>); &nbsp;&nbsp;</span></span>
    <li><span>user_2.setName(</span><span class="string">"Name_2"</span><span>); &nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>Transaction&nbsp;tx&nbsp;=&nbsp;session.begintransaction(); &nbsp;&nbsp;</span>
    <li><span>session.save(user_1); &nbsp;&nbsp;</span>
    <li><span class="comment">//通过session的save方法，user_1对象已经被纳入Hibernate的实体管理容器，处于持久化状 </span><span>&nbsp;&nbsp;</span></span>
    <li><span class="comment">//态(Persistent)，这时候对user_1对象的任何修改都将被同步到数据库中。 </span><span>&nbsp;&nbsp;</span></span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span>tx.commit(); &nbsp;&nbsp;</span>
    <li><span>&nbsp;&nbsp;</span>
    <li><span class="comment">//而user_2仍然才处于自由状态（Transient），不受Hibernate框架的管理。</span><span>&nbsp;&nbsp;</span></span> </li>
</ol>
</div>
<pre style="display: none" class="java" name="code">//创建两个处于自由状态的实体对象。
TUser user_1 = new TUser();
TUser user_2 = new TUser();
user_1.setName("Name_1");
user_2.setName("Name_2");
Transaction tx = session.begintransaction();
session.save(user_1);
//通过session的save方法，user_1对象已经被纳入Hibernate的实体管理容器，处于持久化状
//态(Persistent)，这时候对user_1对象的任何修改都将被同步到数据库中。
tx.commit();
//而user_2仍然才处于自由状态（Transient），不受Hibernate框架的管理。
</pre>
<br />
从上面看到，处于<span style="color: brown">自由状态</span>的实体对象，可以通过Hibernate的Session.sava方法转化为<span style="color: brown">持久状态</span>。 <br />
除了用Session.save方法外，还可以通过其他方法来获取一个<span style="color: brown">持久状态</span>的对象，那就是直接通过Hibernate加载的对象，通过Session.load方法，可以直接加载一个处于<span style="color: brown">持久状态</span>的实体对象。如下： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div>
</div>
<ol class="dp-j">
    <li><span><span>TUser&nbsp;user&nbsp;=&nbsp;Session.load(TUser.</span><span class="keyword">class</span><span>,</span><span class="keyword">new</span><span>&nbsp;Integer(</span><span class="number">1</span><span>)); &nbsp;&nbsp;</span></span>
    <li><span class="comment">//在load方法没返回之前，就已经先把对象纳入Hibernate的管理范围，所以这里的user </span><span>&nbsp;&nbsp;</span></span>
    <li><span class="comment">//已经处于持久状态。</span><span>&nbsp;&nbsp;</span></span> </li>
</ol>
</div>
<pre style="display: none" class="java" name="code">TUser user = Session.load(TUser.class,new Integer(1));
//在load方法没返回之前，就已经先把对象纳入Hibernate的管理范围，所以这里的user
//已经处于持久状态。
</pre>
<br />
从上面的代码可以看出，处于<span style="color: brown">持久状态</span>的实体对象一定要和Session关联，并处于该Session的有效期内。 <br />
<br />
<span style="color: red"><strong>3：游离状态（Detached）</strong></span> <br />
处于<span style="color: brown">持久状态</span>的实体对象，在其关联的Session关闭以后，此实体对象就处于<span style="color: brown">游离状态</span>， <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div>
</div>
<ol class="dp-j">
    <li><span><span>TUser&nbsp;user&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;TUser(); &nbsp;&nbsp;</span></span>
    <li><span>user.setName(</span><span class="string">"name_1"</span><span>); &nbsp;&nbsp;</span></span>
    <li><span>Transaction&nbsp;tx&nbsp;=&nbsp;session.begintransaction(); &nbsp;&nbsp;</span>
    <li><span>session.save(user);</span><span class="comment">//把自由状态的实体对象user转为持久状态， </span><span>&nbsp;&nbsp;</span></span>
    <li><span>tx.commit(); &nbsp;&nbsp;</span>
    <li><span>session.close(); &nbsp;&nbsp;</span>
    <li><span class="comment">//session关闭以后，处于持久状态的实体对象user将转为游离状态。 </span><span>&nbsp;&nbsp;</span></span>
    <li><span class="comment">//因为此时user已经和session脱离关系。</span><span>&nbsp;&nbsp;</span></span> </li>
</ol>
</div>
<pre style="display: none" class="java" name="code">TUser user = new TUser();
user.setName("name_1");
Transaction tx = session.begintransaction();
session.save(user);//把自由状态的实体对象user转为持久状态，
tx.commit();
session.close();
//session关闭以后，处于持久状态的实体对象user将转为游离状态。
//因为此时user已经和session脱离关系。
</pre>
<br />
<br />
由上面可以看到实体对象的<span style="color: brown">游离状态</span>是在对象和它所寄宿的Session脱离关系后形成的，但处于<span style="color: brown">自由状态</span>的实体对象也没有和任何session有关联，那么他们两者有什么区别呢？关键的就在我们对<span style="color: brown">自由状态</span>的实体对象执行了Session.save方法， <br />
当我们执行 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div>
</div>
<ol class="dp-j">
    <li><span><span>TUser&nbsp;user&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;TUser();&nbsp;&nbsp;</span></span> </li>
</ol>
</div>
<pre style="display: none" class="java" name="code">TUser user = new TUser();
</pre>
<br />
时，我们只是创建了一个普通的对象，他并没有和数据库里的任何一条记录对应，当我们执行 <br />
Session.save以后，Hibernate就为user设置了一个主键，就是user.Id属性，通过这个属性，Hibernate就把user对象和数据库里的记录关联起来，所以<span style="color: brown">自由状态</span>和<span style="color: brown">游离状态</span>的基本区别就是 处于<span style="color: brown">游离状态</span>的实体对象，在数据库里有对应的记录，因此它可以通过和session关联再次转为<span style="color: brown">持久状态</span>。 <br />
<br />
<span style="color: red"><strong>三种状态的转化</strong></span> <br />
自由状态--&gt;持久状态：可以通过Session.sava方法来转换。 <br />
持久状态--&gt;游离状态：可以通过Session.close方法来关闭session，获取游离状态的对象 <br />
持久状态--&gt;自由状态：可以通过Session.delete方法来删除实体对象对应的数据库记录，使实体对象处于自由状态。 <br />
<br />
补充一下，有时可能会想，可以通过认为的个处于<span style="color: brown">自由状态</span>的实体对象设置一个Id值 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div>
</div>
<ol class="dp-j">
    <li><span><span>user.Id=</span><span class="number">1</span><span>&nbsp;&nbsp;</span></span> </li>
</ol>
</div>
<pre style="display: none" class="java" name="code">user.Id=1</pre>
，来人为的创建一个<span style="color: brown">游离状态</span>的对象。 <br />
这里注意一点，我们可以人为地给实体对象设置Id值，我我们无法知道这个ID值在数据库里有没有对应的记录，如果没有，就算我们人为地设置了Id，也不能说一个有ID的实体对象就是一个<span style="color: brown">游离状态</span>的对象。</div>
 <img src ="http://www.blogjava.net/lanxin1020/aggbug/264425.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lanxin1020/" target="_blank">lanxin1020</a> 2009-04-08 12:02 <a href="http://www.blogjava.net/lanxin1020/archive/2009/04/08/264425.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>