﻿<?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-Ericzhang5231-文章分类-Hibernate</title><link>http://www.blogjava.net/Ericzhang5231/category/29096.html</link><description /><language>zh-cn</language><lastBuildDate>Sat, 05 Apr 2008 05:51:00 GMT</lastBuildDate><pubDate>Sat, 05 Apr 2008 05:51:00 GMT</pubDate><ttl>60</ttl><item><title>（转）Spring事务传播机制解惑</title><link>http://www.blogjava.net/Ericzhang5231/articles/190896.html</link><dc:creator>Eric5231</dc:creator><author>Eric5231</author><pubDate>Sat, 05 Apr 2008 04:45:00 GMT</pubDate><guid>http://www.blogjava.net/Ericzhang5231/articles/190896.html</guid><wfw:comment>http://www.blogjava.net/Ericzhang5231/comments/190896.html</wfw:comment><comments>http://www.blogjava.net/Ericzhang5231/articles/190896.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ericzhang5231/comments/commentRss/190896.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ericzhang5231/services/trackbacks/190896.html</trackback:ping><description><![CDATA[<p><strong>Spring事务传播机制解惑</strong></p>
<p><strong>概述</strong></p>
<p>当我们调用一个基于Spring的Service接口方法（如UserService#addUser()）时，它将运行于Spring管理的事务环境中，Service接口方法可能会在内部调用其它的Service接口方法以共同完成一个完整的业务操作，因此就会产生服务接口方法嵌套调用的情况，Spring通过事务传播行为控制当前的事务如何传播到被嵌套调用的目标服务接口方法中。</p>
<p>事务传播是Spring进行事务管理的重要概念，其重要性怎么强调都不为过。但是事务传播行为也是被误解最多的地方，在本文里，我们将详细分析不同事务传播行为的表现形式，掌握它们之间的区别。</p>
<p><strong>事务传播行为种类</strong></p>
<p>Spring在TransactionDefinition接口中规定了7种类型的事务传播行为，它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播：</p>
<p><a name="_Ref160706115">表</a>1事务传播行为类型</p>
<p>
<table bordercolor="#cccccc" cellspacing="1" cellpadding="1" border="1">
    <tbody>
        <tr class="textblack">
            <td width="201">
            <p align="center">事务传播行为类型</p>
            </td>
            <td width="358">
            <p align="center">说明</p>
            </td>
        </tr>
        <tr class="textblack">
            <td valign="top" width="201">
            <p>PROPAGATION_REQUIRED</p>
            </td>
            <td valign="top" width="358">
            <p>如果当前没有事务，就新建一个事务，如果已经存在一个事务中，加入到这个事务中。这是最常见的选择。</p>
            </td>
        </tr>
        <tr class="textblack">
            <td valign="top" width="201">
            <p>PROPAGATION_SUPPORTS</p>
            </td>
            <td valign="top" width="358">
            <p>支持当前事务，如果当前没有事务，就以非事务方式执行。</p>
            </td>
        </tr>
        <tr class="textblack">
            <td valign="top" width="201">
            <p>PROPAGATION_MANDATORY</p>
            </td>
            <td valign="top" width="358">
            <p>使用当前的事务，如果当前没有事务，就抛出异常。</p>
            </td>
        </tr>
        <tr class="textblack">
            <td valign="top" width="201">
            <p>PROPAGATION_REQUIRES_NEW</p>
            </td>
            <td valign="top" width="358">
            <p>新建事务，如果当前存在事务，把当前事务挂起。</p>
            </td>
        </tr>
        <tr class="textblack">
            <td valign="top" width="201">
            <p>PROPAGATION_NOT_SUPPORTED</p>
            </td>
            <td valign="top" width="358">
            <p>以非事务方式执行操作，如果当前存在事务，就把当前事务挂起。</p>
            </td>
        </tr>
        <tr class="textblack">
            <td valign="top" width="201">
            <p>PROPAGATION_NEVER</p>
            </td>
            <td valign="top" width="358">
            <p>以非事务方式执行，如果当前存在事务，则抛出异常。</p>
            </td>
        </tr>
        <tr class="textblack">
            <td valign="top" width="201">
            <p>PROPAGATION_NESTED</p>
            </td>
            <td valign="top" width="358">
            <p>如果当前存在事务，则在嵌套事务内执行。如果当前没有事务，则执行与PROPAGATION_REQUIRED类似的操作。</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>当使用PROPAGATION_NESTED时，底层的数据源必须基于JDBC 3.0，并且实现者需要支持保存点事务机制。</p>
<p><strong>几种容易引起误解的组合事务传播行为</strong></p>
<p>当服务接口方法分别使用表1中不同的事务传播行为，且这些接口方法又发生相互调用的情况下，大部分组合都是一目了然，容易理解的。但是，也存在一些容易引起误解的组合事务传播方式。</p>
<p>下面，我们通过两个具体的服务接口的组合调用行为来破解这一难点。这两个服务接口分别是UserService和ForumService，UserSerice有一个addCredits()方法，ForumSerivce#addTopic()方法调用了UserSerice#addCredits()方法，发生关联性服务方法的调用：</p>
<p>public class ForumService {</p>
<p>private UserService userService;</p>
<p>public void <strong>addTopic()</strong>{<strong>①调用其它服务接口的方法</strong></p>
<p>//add Topic&#8230;</p>
<p>userService.<strong>addCredits()</strong>;<strong>②被关联调用的业务方法</strong></p>
<p>}</p>
<p>}</p>
<p>嵌套调用的事务方法</p>
<p>对Spring事务传播行为最常见的一个误解是：当服务接口方法发生嵌套调用时，被调用的服务方法只能声明为PROPAGATION_NESTED。这种观点犯了望文生义的错误，误认为PROPAGATION_NESTED是专为方法嵌套准备的。这种误解遗害不浅，执有这种误解的开发者错误地认为：应尽量不让Service类的业务方法发生相互的调用，Service类只能调用DAO层的DAO类，以避免产生嵌套事务。</p>
<p>其实，这种顾虑是完全没有必要的，PROPAGATION_REQUIRED已经清楚地告诉我们：事务的方法会足够&#8220;聪明&#8221;地判断上下文是否已经存在一个事务中，如果已经存在，就加入到这个事务中，否则创建一个新的事务。</p>
<p>依照上面的例子，假设我们将ForumService#addTopic()和UserSerice#addCredits()方法的事务传播行为都设置为PROPAGATION_REQUIRED，这两个方法将运行于同一个事务中。</p>
<p>为了清楚地说明这点，可以将Log4J的日志设置为DEBUG级别，以观察Spring事务管理器内部的运行情况。下面将两个业务方法都设置为PROPAGATION_REQUIRED，Spring所输出的日志信息如下：</p>
<p>Using transaction object </p>
<p>[org.springframework.jdbc.datasource.DataSourceTransactionManager$DataSourceTransactionObject@e3849c]</p>
<p><strong>①为</strong><strong>ForumService#addTopic()</strong><strong>新建一个事务</strong><strong></strong></p>
<p><strong>Creating new transaction with name [com.baobaotao.service.ForumService.addTopic]:</strong> PROPAGATION_REQUIRED,ISOLATION_DEFAULT</p>
<p>Acquired Connection [org.apache.commons.dbcp.PoolableConnection@dc41c5] for JDBC transaction</p>
<p>Switching JDBC Connection [org.apache.commons.dbcp.PoolableConnection@dc41c5] to manual commit</p>
<p>Bound value [org.springframework.jdbc.datasource.ConnectionHolder@ee1ede] for key [org.apache.commons.dbcp.BasicDataSource@4204] to thread [main]</p>
<p>Initializing transaction synchronization</p>
<p>Getting transaction for [com.baobaotao.service.ForumService.addTopic]</p>
<p>Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@ee1ede] for key [org.apache.commons.dbcp.BasicDataSource@4204] bound to thread [main]</p>
<p>Using transaction object [org.springframework.jdbc.datasource.DataSourceTransactionManager$DataSourceTransactionObject@8b8a47]</p>
<p><strong>②</strong><strong>UserService#addCredits()</strong><strong>简单地加入到已存在的事务中（即①处创建的事务）</strong><strong></strong></p>
<p><strong>Participating in existing transaction</strong></p>
<p>Getting transaction for [com.baobaotao.service.UserService.addCredits]</p>
<p>Completing transaction for [com.baobaotao.service.UserService.addCredits]</p>
<p>Completing transaction for [com.baobaotao.service.ForumService.addTopic]</p>
<p>Triggering beforeCommit synchronization</p>
<p>Triggering beforeCompletion synchronization</p>
<p>Initiating transaction commit</p>
<p><strong>③调用底层</strong><strong>Connection#commit()</strong><strong>方法提交事务</strong></p>
<p>Committing JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@dc41c5]</p>
<p>Triggering afterCommit synchronization</p>
<p>Triggering afterCompletion synchronization</p>
<p>Clearing transaction synchronization</p>
<p>嵌套事务</p>
<p>将ForumService#addTopic()设置为PROPAGATION_REQUIRED时，UserSerice#addCredits()设置为PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS、PROPAGATION_MANDATORY时，运行的效果都是一致的（当然，如果单独调用addCredits()就另当别论了）。</p>
<p>当addTopic()运行在一个事务下（如设置为PROPAGATION_REQUIRED），而addCredits()设置为PROPAGATION_NESTED时，如果底层数据源支持保存点，Spring将为内部的addCredits()方法产生的一个内嵌的事务。如果addCredits()对应的内嵌事务执行失败，事务将回滚到addCredits()方法执行前的点，并不会将整个事务回滚。内嵌事务是内层事务的一部分，所以只有外层事务提交时，嵌套事务才能一并提交。</p>
<p>嵌套事务不能够提交，它必须通过外层事务来完成提交的动作，外层事务的回滚也会造成内部事务的回滚。</p>
<p>嵌套事务和新事务</p>
<p>PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED也是容易混淆的两个传播行为。PROPAGATION_REQUIRES_NEW 启动一个新的、和外层事务无关的&#8220;内部&#8221;事务。该事务拥有自己的独立隔离级别和锁，不依赖于外部事务，独立地提交和回滚。当内部事务开始执行时，外部事务将被挂起，内务事务结束时，外部事务才继续执行。</p>
<p>由此可见， PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于：PROPAGATION_REQUIRES_NEW 将创建一个全新的事务，它和外层事务没有任何关系，而 PROPAGATION_NESTED 将创建一个依赖于外层事务的子事务，当外层事务提交或回滚时，子事务也会连带提交和回滚。</p>
<p>其它需要注意问题</p>
<p>以下几个问题值得注意：</p>
<p>1) 当业务方法被设置为PROPAGATION_MANDATORY时，它就不能被非事务的业务方法调用。如将ForumService#addTopic()设置为PROPAGATION_MANDATORY，如果展现层的Action直接调用addTopic()方法，将引发一个异常。正确的情况是：addTopic()方法必须被另一个带事务的业务方法调用（如ForumService#otherMethod()）。所以PROPAGATION_MANDATORY的方法一般都是被其它业务方法间接调用的。</p>
<p>2) 当业务方法被设置为PROPAGATION_NEVER时，它将不能被拥有事务的其它业务方法调用。假设UserService#addCredits()设置为PROPAGATION_NEVER，当ForumService# addTopic()拥有一个事务时，addCredits()方法将抛出异常。所以PROPAGATION_NEVER方法一般是被直接调用的。</p>
<p>3)当方法被设置为PROPAGATION_NOT_SUPPORTED时，外层业务方法的事务会被挂起，当内部方法运行完成后，外层方法的事务重新运行。如果外层方法没有事务，直接运行，不需要做任何其它的事。</p>
<p><strong>小结</strong></p>
<p>在Spring声明式事务管理的配置中，事务传播行为是最容易被误解的配置项，原因在于事务传播行为名称（如PROPAGATION_NESTED：嵌套式事务）和代码结构的类似性上（业务类方法嵌套调用另一个业务类方法）。这种误解在很多Spring开发者中广泛存在，本文深入讲解了Spring事务传播行为对业务方法嵌套调用的真实影响，希望能帮助读者化解对事务传播行为的困惑。</p>
<img src ="http://www.blogjava.net/Ericzhang5231/aggbug/190896.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ericzhang5231/" target="_blank">Eric5231</a> 2008-04-05 12:45 <a href="http://www.blogjava.net/Ericzhang5231/articles/190896.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>（转）Spring事务传播机制解惑</title><link>http://www.blogjava.net/Ericzhang5231/articles/190895.html</link><dc:creator>Eric5231</dc:creator><author>Eric5231</author><pubDate>Sat, 05 Apr 2008 04:43:00 GMT</pubDate><guid>http://www.blogjava.net/Ericzhang5231/articles/190895.html</guid><wfw:comment>http://www.blogjava.net/Ericzhang5231/comments/190895.html</wfw:comment><comments>http://www.blogjava.net/Ericzhang5231/articles/190895.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ericzhang5231/comments/commentRss/190895.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ericzhang5231/services/trackbacks/190895.html</trackback:ping><description><![CDATA[<p><strong>Spring事务传播机制解惑</strong></p>
<p><strong>概述</strong></p>
<p>当我们调用一个基于Spring的Service接口方法（如UserService#addUser()）时，它将运行于Spring管理的事务环境中，Service接口方法可能会在内部调用其它的Service接口方法以共同完成一个完整的业务操作，因此就会产生服务接口方法嵌套调用的情况，Spring通过事务传播行为控制当前的事务如何传播到被嵌套调用的目标服务接口方法中。</p>
<p>事务传播是Spring进行事务管理的重要概念，其重要性怎么强调都不为过。但是事务传播行为也是被误解最多的地方，在本文里，我们将详细分析不同事务传播行为的表现形式，掌握它们之间的区别。</p>
<p><strong>事务传播行为种类</strong></p>
<p>Spring在TransactionDefinition接口中规定了7种类型的事务传播行为，它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播：</p>
<p><a name="_Ref160706115">表</a>1事务传播行为类型</p>
<p>
<table bordercolor="#cccccc" cellspacing="1" cellpadding="1" border="1">
    <tbody>
        <tr class="textblack">
            <td width="201">
            <p align="center">事务传播行为类型</p>
            </td>
            <td width="358">
            <p align="center">说明</p>
            </td>
        </tr>
        <tr class="textblack">
            <td valign="top" width="201">
            <p>PROPAGATION_REQUIRED</p>
            </td>
            <td valign="top" width="358">
            <p>如果当前没有事务，就新建一个事务，如果已经存在一个事务中，加入到这个事务中。这是最常见的选择。</p>
            </td>
        </tr>
        <tr class="textblack">
            <td valign="top" width="201">
            <p>PROPAGATION_SUPPORTS</p>
            </td>
            <td valign="top" width="358">
            <p>支持当前事务，如果当前没有事务，就以非事务方式执行。</p>
            </td>
        </tr>
        <tr class="textblack">
            <td valign="top" width="201">
            <p>PROPAGATION_MANDATORY</p>
            </td>
            <td valign="top" width="358">
            <p>使用当前的事务，如果当前没有事务，就抛出异常。</p>
            </td>
        </tr>
        <tr class="textblack">
            <td valign="top" width="201">
            <p>PROPAGATION_REQUIRES_NEW</p>
            </td>
            <td valign="top" width="358">
            <p>新建事务，如果当前存在事务，把当前事务挂起。</p>
            </td>
        </tr>
        <tr class="textblack">
            <td valign="top" width="201">
            <p>PROPAGATION_NOT_SUPPORTED</p>
            </td>
            <td valign="top" width="358">
            <p>以非事务方式执行操作，如果当前存在事务，就把当前事务挂起。</p>
            </td>
        </tr>
        <tr class="textblack">
            <td valign="top" width="201">
            <p>PROPAGATION_NEVER</p>
            </td>
            <td valign="top" width="358">
            <p>以非事务方式执行，如果当前存在事务，则抛出异常。</p>
            </td>
        </tr>
        <tr class="textblack">
            <td valign="top" width="201">
            <p>PROPAGATION_NESTED</p>
            </td>
            <td valign="top" width="358">
            <p>如果当前存在事务，则在嵌套事务内执行。如果当前没有事务，则执行与PROPAGATION_REQUIRED类似的操作。</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>当使用PROPAGATION_NESTED时，底层的数据源必须基于JDBC 3.0，并且实现者需要支持保存点事务机制。</p>
<p><strong>几种容易引起误解的组合事务传播行为</strong></p>
<p>当服务接口方法分别使用表1中不同的事务传播行为，且这些接口方法又发生相互调用的情况下，大部分组合都是一目了然，容易理解的。但是，也存在一些容易引起误解的组合事务传播方式。</p>
<p>下面，我们通过两个具体的服务接口的组合调用行为来破解这一难点。这两个服务接口分别是UserService和ForumService，UserSerice有一个addCredits()方法，ForumSerivce#addTopic()方法调用了UserSerice#addCredits()方法，发生关联性服务方法的调用：</p>
<p>public class ForumService {</p>
<p>private UserService userService;</p>
<p>public void <strong>addTopic()</strong>{<strong>①调用其它服务接口的方法</strong></p>
<p>//add Topic&#8230;</p>
<p>userService.<strong>addCredits()</strong>;<strong>②被关联调用的业务方法</strong></p>
<p>}</p>
<p>}</p>
<p>嵌套调用的事务方法</p>
<p>对Spring事务传播行为最常见的一个误解是：当服务接口方法发生嵌套调用时，被调用的服务方法只能声明为PROPAGATION_NESTED。这种观点犯了望文生义的错误，误认为PROPAGATION_NESTED是专为方法嵌套准备的。这种误解遗害不浅，执有这种误解的开发者错误地认为：应尽量不让Service类的业务方法发生相互的调用，Service类只能调用DAO层的DAO类，以避免产生嵌套事务。</p>
<p>其实，这种顾虑是完全没有必要的，PROPAGATION_REQUIRED已经清楚地告诉我们：事务的方法会足够&#8220;聪明&#8221;地判断上下文是否已经存在一个事务中，如果已经存在，就加入到这个事务中，否则创建一个新的事务。</p>
<p>依照上面的例子，假设我们将ForumService#addTopic()和UserSerice#addCredits()方法的事务传播行为都设置为PROPAGATION_REQUIRED，这两个方法将运行于同一个事务中。</p>
<p>为了清楚地说明这点，可以将Log4J的日志设置为DEBUG级别，以观察Spring事务管理器内部的运行情况。下面将两个业务方法都设置为PROPAGATION_REQUIRED，Spring所输出的日志信息如下：</p>
<p>Using transaction object </p>
<p>[org.springframework.jdbc.datasource.DataSourceTransactionManager$DataSourceTransactionObject@e3849c]</p>
<p><strong>①为</strong><strong>ForumService#addTopic()</strong><strong>新建一个事务</strong><strong></strong></p>
<p><strong>Creating new transaction with name [com.baobaotao.service.ForumService.addTopic]:</strong> PROPAGATION_REQUIRED,ISOLATION_DEFAULT</p>
<p>Acquired Connection [org.apache.commons.dbcp.PoolableConnection@dc41c5] for JDBC transaction</p>
<p>Switching JDBC Connection [org.apache.commons.dbcp.PoolableConnection@dc41c5] to manual commit</p>
<p>Bound value [org.springframework.jdbc.datasource.ConnectionHolder@ee1ede] for key [org.apache.commons.dbcp.BasicDataSource@4204] to thread [main]</p>
<p>Initializing transaction synchronization</p>
<p>Getting transaction for [com.baobaotao.service.ForumService.addTopic]</p>
<p>Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@ee1ede] for key [org.apache.commons.dbcp.BasicDataSource@4204] bound to thread [main]</p>
<p>Using transaction object [org.springframework.jdbc.datasource.DataSourceTransactionManager$DataSourceTransactionObject@8b8a47]</p>
<p><strong>②</strong><strong>UserService#addCredits()</strong><strong>简单地加入到已存在的事务中（即①处创建的事务）</strong><strong></strong></p>
<p><strong>Participating in existing transaction</strong></p>
<p>Getting transaction for [com.baobaotao.service.UserService.addCredits]</p>
<p>Completing transaction for [com.baobaotao.service.UserService.addCredits]</p>
<p>Completing transaction for [com.baobaotao.service.ForumService.addTopic]</p>
<p>Triggering beforeCommit synchronization</p>
<p>Triggering beforeCompletion synchronization</p>
<p>Initiating transaction commit</p>
<p><strong>③调用底层</strong><strong>Connection#commit()</strong><strong>方法提交事务</strong></p>
<p>Committing JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@dc41c5]</p>
<p>Triggering afterCommit synchronization</p>
<p>Triggering afterCompletion synchronization</p>
<p>Clearing transaction synchronization</p>
<p>嵌套事务</p>
<p>将ForumService#addTopic()设置为PROPAGATION_REQUIRED时，UserSerice#addCredits()设置为PROPAGATION_REQUIRED、PROPAGATION_SUPPORTS、PROPAGATION_MANDATORY时，运行的效果都是一致的（当然，如果单独调用addCredits()就另当别论了）。</p>
<p>当addTopic()运行在一个事务下（如设置为PROPAGATION_REQUIRED），而addCredits()设置为PROPAGATION_NESTED时，如果底层数据源支持保存点，Spring将为内部的addCredits()方法产生的一个内嵌的事务。如果addCredits()对应的内嵌事务执行失败，事务将回滚到addCredits()方法执行前的点，并不会将整个事务回滚。内嵌事务是内层事务的一部分，所以只有外层事务提交时，嵌套事务才能一并提交。</p>
<p>嵌套事务不能够提交，它必须通过外层事务来完成提交的动作，外层事务的回滚也会造成内部事务的回滚。</p>
<p>嵌套事务和新事务</p>
<p>PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED也是容易混淆的两个传播行为。PROPAGATION_REQUIRES_NEW 启动一个新的、和外层事务无关的&#8220;内部&#8221;事务。该事务拥有自己的独立隔离级别和锁，不依赖于外部事务，独立地提交和回滚。当内部事务开始执行时，外部事务将被挂起，内务事务结束时，外部事务才继续执行。</p>
<p>由此可见， PROPAGATION_REQUIRES_NEW 和 PROPAGATION_NESTED 的最大区别在于：PROPAGATION_REQUIRES_NEW 将创建一个全新的事务，它和外层事务没有任何关系，而 PROPAGATION_NESTED 将创建一个依赖于外层事务的子事务，当外层事务提交或回滚时，子事务也会连带提交和回滚。</p>
<p>其它需要注意问题</p>
<p>以下几个问题值得注意：</p>
<p>1) 当业务方法被设置为PROPAGATION_MANDATORY时，它就不能被非事务的业务方法调用。如将ForumService#addTopic()设置为PROPAGATION_MANDATORY，如果展现层的Action直接调用addTopic()方法，将引发一个异常。正确的情况是：addTopic()方法必须被另一个带事务的业务方法调用（如ForumService#otherMethod()）。所以PROPAGATION_MANDATORY的方法一般都是被其它业务方法间接调用的。</p>
<p>2) 当业务方法被设置为PROPAGATION_NEVER时，它将不能被拥有事务的其它业务方法调用。假设UserService#addCredits()设置为PROPAGATION_NEVER，当ForumService# addTopic()拥有一个事务时，addCredits()方法将抛出异常。所以PROPAGATION_NEVER方法一般是被直接调用的。</p>
<p>3)当方法被设置为PROPAGATION_NOT_SUPPORTED时，外层业务方法的事务会被挂起，当内部方法运行完成后，外层方法的事务重新运行。如果外层方法没有事务，直接运行，不需要做任何其它的事。</p>
<p><strong>小结</strong></p>
<p>在Spring声明式事务管理的配置中，事务传播行为是最容易被误解的配置项，原因在于事务传播行为名称（如PROPAGATION_NESTED：嵌套式事务）和代码结构的类似性上（业务类方法嵌套调用另一个业务类方法）。这种误解在很多Spring开发者中广泛存在，本文深入讲解了Spring事务传播行为对业务方法嵌套调用的真实影响，希望能帮助读者化解对事务传播行为的困惑。</p>
<img src ="http://www.blogjava.net/Ericzhang5231/aggbug/190895.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ericzhang5231/" target="_blank">Eric5231</a> 2008-04-05 12:43 <a href="http://www.blogjava.net/Ericzhang5231/articles/190895.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Transaction always commits even if marked readOnly </title><link>http://www.blogjava.net/Ericzhang5231/articles/Transaction.html</link><dc:creator>Eric5231</dc:creator><author>Eric5231</author><pubDate>Sat, 05 Apr 2008 04:36:00 GMT</pubDate><guid>http://www.blogjava.net/Ericzhang5231/articles/Transaction.html</guid><wfw:comment>http://www.blogjava.net/Ericzhang5231/comments/190892.html</wfw:comment><comments>http://www.blogjava.net/Ericzhang5231/articles/Transaction.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ericzhang5231/comments/commentRss/190892.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ericzhang5231/services/trackbacks/190892.html</trackback:ping><description><![CDATA[Let me first of all state the expected behavior: Silently marking a transaction as rollback-only through a setRollbackOnly call will work as long as you do it at the *outermost* transaction level. If you do it within an inner transaction scope, the outer transaction will see this as a "global" rollback-only and throw an UnexpectedRollbackException - since the code in the outer transaction did not explicitly ask for a rollback, so needs to be notified.<br />
<br />
So in your scenario, I would assume that you do the setRollbackOnly within an inner transaction scope. Since you're using &lt;tx:advice&gt;, this could mean that your pointcut is too broad and applies transaction demarcation at multiple levels: for example, at the Controller level as well as at the service level, with the setRollbackOnly call happening in a service - this would lead to an UnexpectedRollbackException at the Controller level.<br />
<br />
That said, I would actually argue that you should virtually never be using a programmatic setRollbackOnly call in the first place, or more specifically, a rollback without exception thrown to the caller. This usually indicates inappropriate transaction scopes.<br />
<br />
In particular, web data binding should *not* happen within a transaction. Rather, perform data binding without transaction first, then start transactions at the service level *once you decided to process the bound data*, with the bound data brought into the transaction through a merge operation. This way, validation errors don't require a transaction rollback in the first place...<br />
<br />
Aside from avoiding programmatic setRollbackOnly calls in your application code, the above approach to validation and transactions also avoids excessive rollbacks in your transaction statistics. Such rollbacks for frequent and perfectly normal user interactions should in particular be avoided in administered environments like a J2EE server installation - with transaction monitoring and (potentially) escalation messages generated for rollbacks.<br />
<img src ="http://www.blogjava.net/Ericzhang5231/aggbug/190892.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ericzhang5231/" target="_blank">Eric5231</a> 2008-04-05 12:36 <a href="http://www.blogjava.net/Ericzhang5231/articles/Transaction.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用ThreadLocal管理session</title><link>http://www.blogjava.net/Ericzhang5231/articles/186097.html</link><dc:creator>Eric5231</dc:creator><author>Eric5231</author><pubDate>Thu, 13 Mar 2008 09:04:00 GMT</pubDate><guid>http://www.blogjava.net/Ericzhang5231/articles/186097.html</guid><wfw:comment>http://www.blogjava.net/Ericzhang5231/comments/186097.html</wfw:comment><comments>http://www.blogjava.net/Ericzhang5231/articles/186097.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ericzhang5231/comments/commentRss/186097.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ericzhang5231/services/trackbacks/186097.html</trackback:ping><description><![CDATA[<p><span id="zoom">
<p>在利用Hibernate开发DAO模块时，我们和Session打的交道最多，所以如何合理的管理Session，避免Session的频繁创建
和销毁，对于提高系统的性能来说是非常重要的，以往是通过eclipse的插件来自动完成这些代码的，当然效果是不错的，但是总是觉得不爽(没有读懂那些
冗长的代码)，所以现在打算自己实现Session管理的代码。 </p>
<p>我们知道Session是由SessionFactory负责创建的，而SessionFactory的实现是线程安全的，多个并发的
线程可以同时访问一个SessionFactory并从中获取Session实例，那么Session是否是线程安全的呢？很遗憾，答案是否定的。
Session中包含了数据库操作相关的状态信息，那么说如果多个线程同时使用一个Session实例进行CRUD，就很有可能导致数据存取的混乱，你能
够想像那些你根本不能预测执行顺序的线程对你的一条记录进行操作的情形吗？ </p>
<p>在Session的众多管理方案中，我们今天来认识一种名ThreadLocal模式的解决方案。
</p>
<p>早在Java1.2推出之时，Java平台中就引入了一个新的支持：java.lang.ThreadLocal，给我们在编写多线程程序
时提供了一种新的选择。ThreadLocal是什么呢？其实ThreadLocal并非是一个线程的本地实现版本，它并不是一个Thread，而是
thread local
variable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单，
就是为每一个使用某变量的线程都提供一个该变量值的副本，是每一个线程都可以独立地改变自己的副本，而不会和其它线程的副本冲突。从线程的角度看，就好像
每一个线程都完全拥有一个该变量。 </p>
<p>ThreadLocal是如何做到为每一个线程维护变量的副本的呢？其实实现的思路很简单，在ThreadLocal类中有一个Map，用于存储每一个线程的变量的副本。比如下面的示例实现(为了简单，没有考虑集合的泛型)：
</p>
<center>
<table bordercolordark="#ffffff" bordercolorlight="black" align="center" border="1" cellpadding="2" cellspacing="0" width="400">
    <tbody>
        <tr>
            <td style="font-size: 9pt;" bgcolor="#e6e6e6">
            <pre><ccid_code>public  class  ThreadLocal  {<br />
            private  Map  values  =  Collections.synchronizedMap(new  HashMap());<br />
            public  Object  get()  {<br />
            Thread  currentThread  =  Thread.currentThread();  <br />
            Object  result  =  values.get(currentThread);  <br />
            if(result  ==  null&amp;&amp;!values.containsKey(currentThread))  {<br />
            result  =  initialValue();<br />
            values.put(currentThread,  result);  <br />
            }<br />
            return  result;  <br />
            }<br />
            public  void  set(Object  newValue)  {<br />
            values.put(Thread.currentThread(),  newValue);<br />
            }<br />
            public  Object  initialValue()  {<br />
            return  null;  <br />
            }<br />
            }</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</center>
<p>那麽具体如何利用ThreadLocal来管理Session呢？Hibernate官方文档手册的示例之中，提供了一个通过ThreadLocal维护Session的好榜样：
</p>
<center>
<table bordercolordark="#ffffff" bordercolorlight="black" align="center" border="1" cellpadding="2" cellspacing="0" width="400">
    <tbody>
        <tr>
            <td style="font-size: 9pt;" bgcolor="#e6e6e6">
            <pre><ccid_code>public  class  HibernateUtil  {<br />
            public  static  final  SessionFactory  sessionFactory;<br />
            static  {<br />
            try  {<br />
            sessionFactory  =  new  Configuration().configure().buildSessionFactory();<br />
            } catch (Throwable  ex) {<br />
            throw  new  ExceptionInInitializerError(ex);<br />
            }<br />
            }<br />
            public static final ThreadLocal&lt;Session&gt;session=new ThreadLocal&lt;Session&gt;();<br />
            public  static  Session  currentSession()  throws  HibernateException  {<br />
            Session  s  =  session.get();<br />
            if(s  ==  null)  {<br />
            s  =  sessionFactory.openSession();<br />
            session.set(s);<br />
            }<br />
            return  s;<br />
            }<br />
            public  static  void  closeSession()  throws  HibernateException  {<br />
            Session  s  =  session.get();<br />
            if(s  !=  null)  {<br />
            s.close();<br />
            }<br />
            session.set(null);<br />
            }<br />
            }</ccid_code></pre>
            </td>
        </tr>
    </tbody>
</table>
</center>
<p>只要借助上面的工具类获取Session实例，我们就可以实现线程范围内的Session共享，从而避免了线程中频繁的创建和销毁Session实
例。当然，不要忘记在用完后关闭Session。写到这里，想再多说一些，也许大多数时候我们的DAO并不会涉及到多线程的情形，比如我们不会将DAO的
代码写在Servlet之中，那样不是良好的设计，我自己通常会在service层的代码里访问DAO的方法。但是我还是建议采用以上的工具类来管理
Session，毕竟我们不能仅仅考虑今天为自己做什么，还应该考虑明天为自己做什么！ </p>
</span></p>
<img src ="http://www.blogjava.net/Ericzhang5231/aggbug/186097.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ericzhang5231/" target="_blank">Eric5231</a> 2008-03-13 17:04 <a href="http://www.blogjava.net/Ericzhang5231/articles/186097.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring的Hibernate事务管理</title><link>http://www.blogjava.net/Ericzhang5231/articles/184414.html</link><dc:creator>Eric5231</dc:creator><author>Eric5231</author><pubDate>Fri, 07 Mar 2008 02:13:00 GMT</pubDate><guid>http://www.blogjava.net/Ericzhang5231/articles/184414.html</guid><wfw:comment>http://www.blogjava.net/Ericzhang5231/comments/184414.html</wfw:comment><comments>http://www.blogjava.net/Ericzhang5231/articles/184414.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ericzhang5231/comments/commentRss/184414.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ericzhang5231/services/trackbacks/184414.html</trackback:ping><description><![CDATA[Spring声明式事务让我们从复杂的事务处理中得到解脱。使得我们再也无需要去处理获得连接、关闭连接、事务提交和回滚等这些操作。再也无&lt; font color="#ff0000"&gt;需要我们在与事务相
关的方法中处理大量的try&#8230;catch&#8230;finally代码&lt; /font&gt;。 <br />
我们在使用Spring声明式事务时，有一个非常重要的概念就是事务属性。事务属性通常由事务的传播行为，事务的隔离级别，事务的超时值和事务只读标志组成。我们在进行事务划分时，
需要进行事务定义，也就是配置事务的属性。 <br />
Spring 在&gt;TransactionDefinition 接口中定义这些属性,以供PlatfromTransactionManager使用,  PlatfromTransactionManager是spring事务管理的核心接口。 <br />
代码 <br />
TransactionDefinition publicinterfaceTransactionDefinition { <br />
intgetPropagationBehavior(); <br />
intgetIsolationLevel(); <br />
intgetTimeout(); <br />
booleanisReadOnly(); <br />
} <br />
getTimeout()方法，它返回事务必须在多少秒内完成。 <br />
isReadOnly(),事务是否只读，事务管理器能够根据这个返回值进行优化，确保事务是只读的。 <br />
getIsolationLevel()方法返回事务的隔离级别，事务管理器根据它来控制另外一个事务可以看到本事务内的哪些数据。 <br />
<br />
在TransactionDefinition接口中定义了五个不同的事务隔离级别:<br />
<br />
1) ISOLATION_DEFAULT 这是一个 PlatfromTransactionManager默认的隔离级别，使用数据库默认的事务隔离级别.另外四个与JDBC的隔离级别相对应 &lt; br /&gt;
2) ISOLATION_READ_UNCOMMITTED这是事务最低的隔离级别，它充许别外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读，不可重复读和幻像读。<br />
3) ISOLATION_READ_COMMITTED 保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。这种事务隔离级别可以避免脏读出现，但是可
能会出现不可重复读和幻像读。 <br />
4) ISOLATION_REPEATABLE_READ 这种事务隔离级别可以防止脏读，不可重复读。但是可能出现幻像读。它除了保证一个事务不能读取另一个事务未提交的数据外，还保证了避免下面
的情况产生(不可重复读)<br />
<br />
<span style="color: #000000;"><span style="color: #000000;"> 在TransactionDefinition接口中定义了七个事务传播行为:<br />
1) &lt; span style="color: #000000;"&gt; PROPAGATION_REQUIRED 如果存在一个事务，则支持当前事务。如果没有事务则开启一个新的事务; </span><br />
</font>2) PROPAGATION_SUPPORTS 如果存在一个事务，支持当前事务。如果没有事务，则非事务的执行;<br />
3) PROPAGATION_MANDATORY 如果已经存在一个事务，支持当前事务。如果没有一个活动的事务，则抛出异;<br />
4)PROPAGATION_REQUIRES_NEW 总是开启一个新的事务。如果一个事务已经存在，则将这个存在的事务挂起;<br />
5) PROPAGATION_NOT_SUPPORTED总是非事务地执行，并挂起任何存在的事务;<br />
6) PROPAGATION_NEVER总是非事务地执行，如果存在一个活动事务，则抛出异常;<br />
7) PROPAGATION_NESTED如果一个活动的事务存在，则运行在一个嵌套的事务中. 如果没有活动事务, 则按
TransactionDefinition.PROPAGATION_REQUIRED 属性执行;<br />
<br />
<br />

<img src ="http://www.blogjava.net/Ericzhang5231/aggbug/184414.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ericzhang5231/" target="_blank">Eric5231</a> 2008-03-07 10:13 <a href="http://www.blogjava.net/Ericzhang5231/articles/184414.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Hibernate的Load和get方法区别</title><link>http://www.blogjava.net/Ericzhang5231/articles/184412.html</link><dc:creator>Eric5231</dc:creator><author>Eric5231</author><pubDate>Fri, 07 Mar 2008 01:55:00 GMT</pubDate><guid>http://www.blogjava.net/Ericzhang5231/articles/184412.html</guid><wfw:comment>http://www.blogjava.net/Ericzhang5231/comments/184412.html</wfw:comment><comments>http://www.blogjava.net/Ericzhang5231/articles/184412.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ericzhang5231/comments/commentRss/184412.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ericzhang5231/services/trackbacks/184412.html</trackback:ping><description><![CDATA[<font color="#3366ff"><strong>1.读取时机不同（当lazy=true的时候）</strong></font><br />
&nbsp;&nbsp;&nbsp;  load是采用延迟机制(<font color="#ff0000">load语句不读库，等使用非主键时才去读库</font>)，而get不采用延迟机制(<font color="#ff0000">get语句时马上读库</font>)；<br />
<br />
<font color="#3366ff"><strong>2.搜索不到数据时的情况</strong></font><br />
&nbsp;&nbsp;&nbsp;  当搜索的数据不存在的时候，load依然会返回一个对象，在你使用该对象的非主键数据时，会抛出异常；<br />
&nbsp;&nbsp;&nbsp;  当搜索的数据不存在的时候，get会返回一个null；<br />
<br />
<font color="#3366ff"><strong>备注：</strong></font><strong><font color="#0000ff">网上看来说load比get更节省资源；</font></strong><br />
&nbsp;&nbsp;&nbsp;  我做过一个例子，即两个线程，1号线程把数据读出来，把session关掉。过几秒2号线程也去读相同的记录，这时2号线程并没有搜索库(没有显示出HQL语句)，不管你用load还是get<br />
&nbsp;&nbsp;&nbsp;  结论：我觉得它们两个都有使用到缓存，至于更深入的我没有去研究了
<img src ="http://www.blogjava.net/Ericzhang5231/aggbug/184412.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ericzhang5231/" target="_blank">Eric5231</a> 2008-03-07 09:55 <a href="http://www.blogjava.net/Ericzhang5231/articles/184412.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第十三章 管理Hibernate的缓存</title><link>http://www.blogjava.net/Ericzhang5231/articles/180726.html</link><dc:creator>Eric5231</dc:creator><author>Eric5231</author><pubDate>Tue, 19 Feb 2008 09:34:00 GMT</pubDate><guid>http://www.blogjava.net/Ericzhang5231/articles/180726.html</guid><wfw:comment>http://www.blogjava.net/Ericzhang5231/comments/180726.html</wfw:comment><comments>http://www.blogjava.net/Ericzhang5231/articles/180726.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ericzhang5231/comments/commentRss/180726.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ericzhang5231/services/trackbacks/180726.html</trackback:ping><description><![CDATA[Session缓存其实就是一块内存空间,在这个内存空间中存放了互相关联的Java对象,Session负责根据持久化对象的状态变化来同步更新数据库.Session的缓存是内置的,不能被卸载,也被称为Hibernate的第一级缓存,此外SessionFactory有一个内置的缓存和一个外置的缓存,其中外置的缓存是可插拔的缓存插件,也被称为Hibernate的第二级缓存,在默认情况下,SessionFactory不会启动这个缓存插件.<br />
<br />
缓存的范围和缓存的并发访问策略<br />
1.持久层的缓存范围<br />
&nbsp;&nbsp; &nbsp;事务范围:&nbsp;&nbsp; &nbsp;缓存只能被当前事务访问,缓存的生命周期依赖于事务的生命周期.每个事务都有独自的缓存<br />
&nbsp;&nbsp; &nbsp;进程范围:&nbsp; 缓存被进程内的所有事务共享,缓存的生命周期依赖于进程的生命周期. 因为进程的事务有可能并发访问缓存,所以必须对缓存采取必要的事务隔离机制;<br />
&nbsp;&nbsp; &nbsp;群集范围: 在群集环境中, 缓存被同一个机器或多个机器上的多个进程共享. 缓存中的数据被复制到集群环境中的每个进程节点,进程之间通过远程通信来保证缓存中数据的一致性,<br />
<br />
缓存中的数据通常采用对象的散装数据形式;<br />
2.缓存并发访问策略<br />
&nbsp;&nbsp; &nbsp;由上可见, 进程范围或群集范围缓存,即第二级缓存,会出现并发问题.对第二级缓存可以设定以下四种类型的并发访问策略,每一个策略对应一种事务隔离级别.<br />
&nbsp;&nbsp; &nbsp;1) 事务型:&nbsp;&nbsp; &nbsp;仅仅在受管理环境中适用,对于经常被读但是很少被修改的数据,可以防止脏读和不可重复读的并发问题;<br />
&nbsp;&nbsp; &nbsp;2)读写型:&nbsp;&nbsp; &nbsp;仅仅在非群集的环境中适用,对于经常被读但是很少被修改的数据,可以防止脏读;<br />
&nbsp;&nbsp; &nbsp;3)非严格读写型: 不保证缓存与数据库中数据的一致性,对于极少被修改,并且允许偶尔脏读的数据,可以采用这种策略;<br />
&nbsp;&nbsp; &nbsp;4)只读型: 对于从来不会被修改的数据,如参考数据,可以使用这个策略;<br />
<br />
只有符合以下条件的数据才适合于存放到第二级缓存中:<br />
&nbsp;&nbsp; &nbsp;1) 很少被修改的数据;<br />
&nbsp;&nbsp; &nbsp;2) 不是很重要的数据,允许出现偶尔的并发问题;<br />
&nbsp;&nbsp; &nbsp;3)不会被并发访问的数据;<br />
&nbsp;&nbsp; &nbsp;4)参考数据;<br />
<br />
Hibernate的二级缓存SessionFactory是进程范围或群集范围的缓存,因此需要采用适当的并发访问策略,提供事务隔离级别,而且可以在每个类或每个集合的粒度上配置第二级缓存.缓存适配器(Cache Provider)用于把具体的缓存实现软件于Hibernate集成.Hibernate还为查询结果提供了一个查询缓存,它依赖于第二级缓存.<br />
<br />
<br />
<br />
管理Hibernate的第一级缓存<br />
&nbsp;&nbsp; &nbsp;Session为应用程序提供了两个管理缓存方法evict(Object o)和clear()<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;evict(Object o) : 从缓存中清除参数指定的持久化对象;(适用于不希望session'按照该对象的状态变化来同步更新数据库和批量更新或批量删除的场合)<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;clear(): 清空缓存中所有持久化对象<br />
*对于更好的批量更新或者批量删除的场合应该直接通过JDBC API访问数据库的过程, 执行SQL语句来减少Hibernate API的多次sql执行, 或者调用相关的存储过程. 这个时候还得注意<br />
<br />
Transaction接口来声明事务边界;<br />
<br />
管理Hibernate的第二级缓存<br />
&nbsp;&nbsp; &nbsp;由于第二级缓存是可配置的插件,Hibernate允许选用以下类型的缓存插件:<br />
&nbsp;&nbsp; &nbsp;1) EHCache: 进程范围内的缓存, 对Hibernate的查询缓存提供了支持;(net.sf.hibernate.cache.EhCacheProvider EHCache插件的适配器)<br />
&nbsp;&nbsp; &nbsp;2) OpenSymphony OSCache: 进程范围内的缓存,提供了丰富的缓存数据过期策略,对Hibernate的查询缓存提供了支持;(net.sf.hibernate.cache,OSCacheProvider OSCache插件<br />
<br />
的适配器);<br />
&nbsp;&nbsp; &nbsp;3) SwarmCache: 群集范围的缓存,但不支持Hibernate的查询缓存;(net.sf.hibernate.cache.SwarmCacheProvider SwarmCache插件的适配器)<br />
&nbsp;&nbsp; &nbsp;4) JBossCache: 群集范围内的缓存,支持事务并发访问策略,对Hibernate的查询缓存提供了支持;(net.sf.hibernate,cache.TreeCacheProvider JBossCache插件的适配器)<br />
<br />
<br />
配置第二级缓存主要包含以下步骤:<br />
&nbsp;&nbsp; &nbsp;1) 在各个映射文件中为持久化类设置第二级缓存后者在Hibernate的配置文件hibernate.cfg.xml中集中设置第二级缓存,设置它的命名缓存的并发访问策略;<br />
&nbsp;&nbsp; &nbsp;2)选择合适的缓存插件,手工编辑配置文件,为每个命名缓存设置数据过期策略;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;class name="mypack.Category" table="CATEGORIES"&gt;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;cache usage="read-write"/&gt;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;id name="id" type="long" column="ID"&gt;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;...<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;/class&gt;<br />
*如果只在category中配置cache,当调用category.getItems().iterate()方法时,Hibernate只会把items集合中的元素存放到缓存中,此时Hibernate仅仅把与Category关联的Item对象的OID存放<br />
<br />
到缓存中.如果希望把整个Item对象散装数据存入缓存,应该在Item.hbm.xml文件中设置cache元素<br />
<br />
<br />
<br />
***************************************************************************************************************************************************<br />
在默认情况下,Session会在下面的时间点清理缓存.<br />
&nbsp;&nbsp; &nbsp;1) 当应用程序调用net.sf.hibernate.Transaction的commit()方法的时候,commit()方法先清理缓存, 然后再向数据库提交事务;<br />
&nbsp;&nbsp; &nbsp;2) 当应用程序调用Session的find()或者iterate()时, 如果缓存中持久化对象的属性发生了变化, 就会先清理缓存, 以保证查询结果能反映持久化对象的最新状态;<br />
&nbsp;&nbsp; &nbsp;3) 当应用程序显式调用Session的flush()方法的时候; <br />
<br />
1. Session的save()方法<br />
&nbsp;&nbsp; &nbsp;save方法并不立即执行SQL insert语句, 只有当Session清理缓存的时, 才会执行SQL insert语句.如果在save()方法之后, 又修改了持久化对象的属性, 这会使得Session在清理缓<br />
<br />
存时, 额外执行SQL update语句.<br />
2. Session的update()方法<br />
&nbsp;&nbsp; &nbsp;update方法会生成或调用一个计划的update语句,并且Session只有在清理缓存的时候才会执行update语句,在执行时才会把Customer对象当前的属性值组装到update语句中.<br />
**通过update()方法使游离对象被一个Session关联,即使没有修改Customer对象的任何属性,Session在清理缓存时也会执行由update()方法计划的update语句. 如果希望Session仅仅当修<br />
<br />
改了Customer对象的属性时, 才执行update语句, 可以把映射文件中&lt;class&gt;元素的select-before-update设为true, 该属性的默认值为false;<br />
**当update()方法关联一个游离对象时, 如果在Session的缓存中已经存在相同OID的持久化对象,会抛出异常.<br />
3. Session的saveOrUpdate()方法<br />
&nbsp;&nbsp; &nbsp;saveOrUpdate()方法同时包含了save()与update()方法的功能, 如果传入的参数是临时对象就调用save()方法; 如果传入的参数是游离对象, 就调用update()方法; 如果传入的参数<br />
<br />
是持久化对象, 那就直接返回.<br />
4. Session的load()和get()方法<br />
&nbsp;&nbsp; &nbsp;Session的load()和get()方法都能根据给定的OID从数据库中加载一个持久化对象, 这两个方法的区别在于: 当数据库中不存在与OID对应的记录时, load()方法抛出<br />
<br />
net.sf.hibernate.ObjectNotFoundException异常,而get()返回null.<br />
5. Session的delete()方法<br />
&nbsp;&nbsp; &nbsp;如果传入的参数是持久化对象, Session就计划执行一个delete语句. 如果传入的参数是游离对象, 先使游离对象被Session关联, 使它变为持久化对象, 然后计划执行一个delete语<br />
<br />
句. Session只有在清理缓存的时候才会执行delete语句. <br />
&nbsp;&nbsp; &nbsp;该方法也能删除多个对象, 但不推荐,效率低.如 session.delete("from Customer as c where c.id&gt;8");
<img src ="http://www.blogjava.net/Ericzhang5231/aggbug/180726.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ericzhang5231/" target="_blank">Eric5231</a> 2008-02-19 17:34 <a href="http://www.blogjava.net/Ericzhang5231/articles/180726.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第十一章 Hibernate的检索方式</title><link>http://www.blogjava.net/Ericzhang5231/articles/query.html</link><dc:creator>Eric5231</dc:creator><author>Eric5231</author><pubDate>Mon, 18 Feb 2008 08:11:00 GMT</pubDate><guid>http://www.blogjava.net/Ericzhang5231/articles/query.html</guid><wfw:comment>http://www.blogjava.net/Ericzhang5231/comments/180482.html</wfw:comment><comments>http://www.blogjava.net/Ericzhang5231/articles/query.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ericzhang5231/comments/commentRss/180482.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ericzhang5231/services/trackbacks/180482.html</trackback:ping><description><![CDATA[HQL:<br />
CreateQuery()<br />
&nbsp;&nbsp; &nbsp;Query query = session.createQuery("from Customer as c where c.name=:customerName and c.age=:customerAge");<br />
&nbsp;&nbsp; &nbsp;query.setString("customerName","Tom");<br />
&nbsp;&nbsp; &nbsp;query.setInteger("customerAge",21);<br />
<br />
createQuery()支持方法链编程风格<br />
<br />
QBC:(Criteria,Criterion,Expression)<br />
&nbsp;&nbsp; &nbsp;Criteria criteria = session.createCriteria(Customer.class);<br />
&nbsp;&nbsp; &nbsp;Criterion criterion1 = Expression.like("name", "T%");<br />
&nbsp;&nbsp; &nbsp;Criterion criterion2 = Expression.like("age", new Integer(21));<br />
&nbsp;&nbsp; &nbsp;Criteria = criteria.add(criterion1).add(criterion2);<br />
&nbsp;&nbsp; &nbsp;List result = criteria.list();<br />
<br />
HQL&amp;&amp;QBC支持多态和继承查询<br />
HQL&amp;&amp;QBC支持排序和分页<br />
&nbsp;&nbsp; &nbsp;HQL: Query query = session.createQuery("from Customer c order by c. name asc, c.age desc"); //排序<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; query.setFirstResult(10);&nbsp; //设定从对象开始检索起始位置为0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; query.setMaxResults(10); //设定一次最多检索出的对象数目<br />
&nbsp;&nbsp; &nbsp;QBC: Criteria criteria = session.createCriteria(Customer.class);<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; criteria.addOrder(Order.asc("name"));<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; criteria.addOrder(Order.desc("age"));<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; criteria.setFirstResult(0); //设定从对象开始检索起始位置为0<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; criteria.setMaxResult(10); //设定一次最多检索出的对象数目<br />
<br />
参数绑定能有效避免一些安全漏洞<br />
<br />
HIbernate还能在xml文件里面配置HQL或者SQL本地查询语句:<br />
&nbsp;&nbsp; &nbsp;//for HQL<br />
&nbsp;&nbsp; &nbsp;&lt;hibernate-mapping&gt;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;class name="mypack.Customer" table="CUSTOMERS"&gt;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/class&gt;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;query name="findCustomersByName"&gt;&lt;![CDATA[from Customer c where c.name like :name]]&gt;&lt;/query&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/hibernate-mapping&gt;<br />
&nbsp;&nbsp; &nbsp;//for SQL<br />
&nbsp;&nbsp; &nbsp;&lt;sql-query name="findCustomersByName"&gt;&lt;![CDATA[select {c.*} from CUSTOMERS c where c.NAME like :name]]&gt;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&lt;return alias="c" class="Customer"/&gt;<br />
&nbsp;&nbsp; &nbsp;&lt;/sql-query&gt;<br />
&nbsp;&nbsp; &nbsp;在程序中使用getNamedQuery()方法获得查询语句:<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Query query = session.getNamedQuery("findCustomersByName");<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;query.setString("name",name);<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;List result = query.list();<br />
<br />
<br />
内连接：利用内连接可获取两表的公共部分的记录Select * from A JOIN B ON A.Aid=B.Bnameid<br />
<br />
<br />
当查询的只是对象的部分属性的时候, 可以采用动态实例化查询结果,把实体的部分属性封装为一个javabean临时对象,不需要创建对象-关系映射文件<br />
&nbsp;&nbsp; &nbsp;package mypack;<br />
&nbsp;&nbsp; &nbsp;import java.io.Serializable;<br />
&nbsp;&nbsp; &nbsp;public class CustomerRow implements Serializable{<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;private Long id;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;private String name;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;private String orderNumber;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;public CustomerRow(Long id, String name, String orderNumber){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;this,id=id;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;...<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;...<br />
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;此处省略id,name和orderNumber属性的get和set方法<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;...<br />
&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;在程序中可以结合HQL查询语句这样使用,<br />
&nbsp;&nbsp; &nbsp;Iterator it = session.createQuery("select new mypack.CustomerRow(c.id,c.name,o.orderNumber)' <br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;+'from Customer c join c,orders o where o,orderNumber like 'T%'").list().iterator();<br />
&nbsp;&nbsp; &nbsp;此外如果结果集只有一个结果,可以用uniqueResult()方法<br />
&nbsp;&nbsp; &nbsp;Object[] obj = (Object[])session.createQuery("select max(c.age),min(c.age) from Customer c").uniqueResult();<br />
&nbsp;&nbsp; &nbsp;Integer maxAge = (Integer) obj[0];<br />
&nbsp;&nbsp; &nbsp;Integer minAge = (Integer) obj[1];<br />
<br />
结果集中可以通过利用set和sql的distinct去掉<br />
<br />
动态查询适宜用QBC检索方式,可以简化编程:<br />
&nbsp;&nbsp; &nbsp;public List findCustomers (String name, int age) throws HibernateException{<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;Criteria criteria = session,createCriteria(Customer,class);<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if(name != null){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;criteria.add(Expression.like("name",nam.toLowerCase(),MactchMode.ANYWHWERE));&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if(age!=0){<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;crteria.add(Expression.eq("age",new Integer(age)));<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return criteria.list();<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;<br />
&nbsp;&nbsp; &nbsp;}<br />
<br />
集合过滤: 当orders集合由于使用延迟检索策略而没有在开始被初始化,当调用get***().iterator()方法初始化的时候不能对这个集合进行排序或者条件过滤,通过使<br />
<br />
用集合过滤就能解决这个问题:<br />
&nbsp;&nbsp; &nbsp;List result = session.createFilter(customer.getOrders(), "where this.price&gt;100 order by this.price")&nbsp; .list();<br />
集合过滤除了用于为集合排序或设置约束条件,还可以:<br />
&nbsp;&nbsp; &nbsp;1) 为集合分页<br />
&nbsp;&nbsp; &nbsp;List result = session.createFilter(customer.getOrders(), "order by this,price asc")<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.setFirstResult(10)<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.setMaxResult(50)<br />
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;.list();<br />
&nbsp;&nbsp; &nbsp;2)只选择集合的某个属性<br />
&nbsp;&nbsp; &nbsp;List result = session.createFilter(customer.getOrders(), "select this.orderNumber").list();
<img src ="http://www.blogjava.net/Ericzhang5231/aggbug/180482.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ericzhang5231/" target="_blank">Eric5231</a> 2008-02-18 16:11 <a href="http://www.blogjava.net/Ericzhang5231/articles/query.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第九章 Hibernate的映射类型</title><link>http://www.blogjava.net/Ericzhang5231/articles/hibernateMappingType.html</link><dc:creator>Eric5231</dc:creator><author>Eric5231</author><pubDate>Thu, 24 Jan 2008 07:57:00 GMT</pubDate><guid>http://www.blogjava.net/Ericzhang5231/articles/hibernateMappingType.html</guid><wfw:comment>http://www.blogjava.net/Ericzhang5231/comments/177518.html</wfw:comment><comments>http://www.blogjava.net/Ericzhang5231/articles/hibernateMappingType.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ericzhang5231/comments/commentRss/177518.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ericzhang5231/services/trackbacks/177518.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;Hibernate映射类型分为两种：内置的映射类型和客户化映射类型。内置映射类型负责把一些常见的Java类型映射到相应的SQL类型；此外，Hibernate还允许用户实现UserType或CompositeUserType接口，来灵活地定制客户化映射类型<br />
<br />
1.内置映射类型<br />
&nbsp;&nbsp; 1).Java基本类型的Hibernate映射类型<br />
<table style="width: 1005px; height: 392px" cellspacing="2" cellpadding="2" width="1005" border="0">
    <tbody>
        <tr>
            <td>Java类型</td>
            <td>Hibernate映射类型</td>
            <td>标准SQL类型</td>
            <td>大小和取值范围</td>
        </tr>
        <tr>
            <td>int/Integer</td>
            <td>int/integer</td>
            <td>INTEGER</td>
            <td>4Byte</td>
        </tr>
        <tr>
            <td>long/Long&nbsp;&nbsp;&nbsp;</td>
            <td>long</td>
            <td>BIGINT</td>
            <td>8Byte</td>
        </tr>
        <tr>
            <td>short/Short</td>
            <td>short</td>
            <td>SAMLLINT</td>
            <td>2Byte</td>
        </tr>
        <tr>
            <td>byte/Byte</td>
            <td>byte</td>
            <td>TINYINT</td>
            <td>1Byte</td>
        </tr>
        <tr>
            <td>float/Float</td>
            <td>float</td>
            <td>FLOAT</td>
            <td>4Byte</td>
        </tr>
        <tr>
            <td>double/Double</td>
            <td>double</td>
            <td>DOUBLE</td>
            <td>8Byte</td>
        </tr>
        <tr>
            <td>BigDecimal</td>
            <td>big_decimal</td>
            <td>NUMBERIC</td>
            <td>Numeric(8,2)</td>
        </tr>
        <tr>
            <td>char/Character/String</td>
            <td>character</td>
            <td>CHAR(1)</td>
            <td>定长字符</td>
        </tr>
        <tr>
            <td>String</td>
            <td>string</td>
            <td>VARCHAR</td>
            <td>变长字符</td>
        </tr>
        <tr>
            <td>boolean/Boolean</td>
            <td>boolean</td>
            <td>BIT</td>
            <td>布尔类型</td>
        </tr>
        <tr>
            <td>boolean/Boolean</td>
            <td>yes/no</td>
            <td>CHAR(1)('Y'/'N')</td>
            <td>布尔类型</td>
        </tr>
        <tr>
            <td>boolean/Boolean</td>
            <td>true/false</td>
            <td>CHAR(1)('T'/'F')</td>
            <td>布尔类型</td>
        </tr>
    </tbody>
</table>
<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;2). Java时间和日期类型的Hibernate映射类型<br />
<table style="width: 1009px; height: 230px" cellspacing="2" cellpadding="2" width="1009" border="0">
    <tbody>
        <tr>
            <td>Java类型</td>
            <td>Hibernate映射类型</td>
            <td>标准SQL类型</td>
            <td>描述</td>
        </tr>
        <tr>
            <td>java.util.Date/java.sql.Date</td>
            <td>date</td>
            <td>DATE</td>
            <td>日期，yyyy-mm-dd</td>
        </tr>
        <tr>
            <td>java.util.Date/java.sql.TIme</td>
            <td>time</td>
            <td>TIME</td>
            <td>时间，hh：mm：ss</td>
        </tr>
        <tr>
            <td>java.util.Date/java.sql.Timestamp</td>
            <td>timestamp</td>
            <td>TIMESTAMP</td>
            <td>时间戳，yyyymmddhhmmss</td>
        </tr>
        <tr>
            <td>java.util.Calendar</td>
            <td>calendar</td>
            <td>TIMESTAMP</td>
            <td>同上</td>
        </tr>
        <tr>
            <td>java.util.Calendar</td>
            <td>calendar_date</td>
            <td>DATE</td>
            <td>日期，yyyy-mm-dd</td>
        </tr>
    </tbody>
</table>
<br />
* 当程序类型为java.sql.Timestamp, 数据库中表属性类型为timestamp的情况下，即使用户以空值插入数据，数据库系统仍然会自动填充timestamp的值<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;3). Java 大对象类型的Hibernate映射类型<br />
<table style="width: 1007px; height: 139px" cellspacing="2" cellpadding="2" width="1007" border="0">
    <tbody>
        <tr>
            <td>Java类型</td>
            <td>Hibernate映射类型</td>
            <td>标准SQL类型</td>
            <td>MySql类型</td>
            <td>Oracle类型</td>
        </tr>
        <tr>
            <td>byte[]</td>
            <td>binary</td>
            <td>VARBINARY/BLOB</td>
            <td>BLOB</td>
            <td>BLOB</td>
        </tr>
        <tr>
            <td>String</td>
            <td>text</td>
            <td>CLOB</td>
            <td>TEXT</td>
            <td>CLOB</td>
        </tr>
        <tr>
            <td>serializable</td>
            <td>实现serializable接口的一个java类</td>
            <td>VARBINARY/BLOB</td>
            <td>BLOB</td>
            <td>BLOB</td>
        </tr>
        <tr>
            <td>java.sql.Clob</td>
            <td>clob</td>
            <td>CLOB</td>
            <td>TEXT</td>
            <td>CLOB</td>
        </tr>
        <tr>
            <td>java.sql.Blob</td>
            <td>blob</td>
            <td>BLOB</td>
            <td>BLOB</td>
            <td>BLOB</td>
        </tr>
    </tbody>
</table>
*&nbsp; 在应用程序中通过Hibernate来保存java.sql.Clob或者java.sql.Blob实例时，必须包含两个步骤：<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;a. 在一个数据库事务中先保存一个空的Blob或Clob实例；b. 接着锁定这条记录，更新在步骤（1）中保存的Blob或Clob实例，把二进制数据或长文本数据写到Blob或Clob实例中。<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #008080">&nbsp;1</span><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #000000"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />
</span><span style="color: #008080">&nbsp;2</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />Session&nbsp;session&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;sessionFactory.openSession();<br />
</span><span style="color: #008080">&nbsp;3</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />Transaction&nbsp;tx&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;session.beginTransaction();<br />
</span><span style="color: #008080">&nbsp;4</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />Customer&nbsp;customer&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">new</span><span style="color: #000000">&nbsp;Customer();<br />
</span><span style="color: #008080">&nbsp;5</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />customer.setDescription(Hibernate.createClob(</span><span style="color: #000000">""</span><span style="color: #000000">));&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">先保存一个空的clob</span><span style="color: #008000"><br />
</span><span style="color: #008080">&nbsp;6</span><span style="color: #008000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000">session.save(customer);<br />
</span><span style="color: #008080">&nbsp;7</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />session.flush();<br />
</span><span style="color: #008080">&nbsp;8</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #008000">//</span><span style="color: #008000">锁定这条记录</span><span style="color: #008000"><br />
</span><span style="color: #008080">&nbsp;9</span><span style="color: #008000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000">session.refresh(customer,LockMode.UPGRADE);<br />
</span><span style="color: #008080">10</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />oracle.sql.CLOB&nbsp;clob&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;(oracle.sql.CLOB)&nbsp;customer.getDescription();<br />
</span><span style="color: #008080">11</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />java.io.Writer&nbsp;pw&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;clob.getCharacterOutStream();<br />
</span><span style="color: #008080">12</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />pw.write(longText);</span><span style="color: #008000">//</span><span style="color: #008000">longText是一个长度超过255的字符串</span><span style="color: #008000"><br />
</span><span style="color: #008080">13</span><span style="color: #008000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000">pw.close();<br />
</span><span style="color: #008080">14</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />tx.commit();<br />
</span><span style="color: #008080">15</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />session.close();</span></div>
<br />
*&nbsp; 一个java类型对应多个Hibernate映射类型的场合。例如，如果持久化类的属性为java.util.Date类型，对应的Hibernate映射类型可以是date,time<br />
或timestamp。此时必须根据对应的数据库表的字段的SQL类型，来确定Hibernate映射类型。如果字段为Date类型，则hibernate映射为datge，如果为TIME则为time，如果为TIMESTAMP则为timestamp。<br />
<br />
<br />
2.客户化映射类型<br />
&nbsp;&nbsp;&nbsp;&nbsp; （很麻烦的一个东西，稍微看了看，日后需要再研究并总结）
 <img src ="http://www.blogjava.net/Ericzhang5231/aggbug/177518.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ericzhang5231/" target="_blank">Eric5231</a> 2008-01-24 15:57 <a href="http://www.blogjava.net/Ericzhang5231/articles/hibernateMappingType.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第八章 映射组成关系</title><link>http://www.blogjava.net/Ericzhang5231/articles/AggregationRelation.html</link><dc:creator>Eric5231</dc:creator><author>Eric5231</author><pubDate>Wed, 23 Jan 2008 12:47:00 GMT</pubDate><guid>http://www.blogjava.net/Ericzhang5231/articles/AggregationRelation.html</guid><wfw:comment>http://www.blogjava.net/Ericzhang5231/comments/177362.html</wfw:comment><comments>http://www.blogjava.net/Ericzhang5231/articles/AggregationRelation.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ericzhang5231/comments/commentRss/177362.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ericzhang5231/services/trackbacks/177362.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp;1. 建立域模型和关系数据模型有着不同的出发点：域模型是由程序代码组成的，通过细化持久化类的粒度来提高代码可重用性，简化编程；而关系数据模型是由关系数据组成的，在存在数据冗余的情况下，可以把粗粒度的表拆分成具有外键参照关系的几个细粒度表，此外在没有数据冗余的情况下应该尽可能减少表的数目，简化表之间的参照关系。<br />
&nbsp;&nbsp;&nbsp;&nbsp;域模型中的聚集aggregation对象关系在关系数据模型中可以通过映射为组成关系来提高代码和数据库访问质量。比如说一个customer具有homeAddress和comAddress属性，从域模型出发，应该把homeAddress和comAddress抽取出来成为一个过程对象。而在关系数据模型中可以通过hibernate提供的组成关系进行映射。映射文件如下：<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #008080">1</span><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #000000">&lt;</span><span style="color: #000000">component&nbsp;name</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">homeAddress</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">com.homeAddress</span><span style="color: #000000">"</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #008080">2</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">parent&nbsp;name</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">customer</span><span style="color: #000000">"</span><span style="color: #000000">/&gt;</span><span style="color: #000000"><br />
</span><span style="color: #008080">3</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">property&nbsp;name</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">street</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;type</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">String</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;column</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">HOME_STREET</span><span style="color: #000000">"</span><span style="color: #000000">/&gt;</span><span style="color: #000000"><br />
</span><span style="color: #008080">4</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">property&nbsp;name</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">city</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;type</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">String</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;column</span><span style="color: #000000">=</span><span style="color: #000000">"</span><span style="color: #000000">HOME_CITY</span><span style="color: #000000">"</span><span style="color: #000000">/&gt;</span><span style="color: #000000"><br />
</span><span style="color: #008080">5</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />
</span><span style="color: #008080">6</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000">&lt;/</span><span style="color: #000000">component</span><span style="color: #000000">&gt;</span></div>
这样进行映射后，并不需要为homeAddress和comAddress单独设置数据库表，应该把homeAddress和comAddress的属性都和customer表放在一起<br />
而有一点要格外注意的是，域模型的组成对象homeAddress和comAddress对象除了具有一般的属性成员变量外，需要为hibernate提供一个parent属性，如下所示<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #008080">&nbsp;1</span><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #000000">packge&nbsp;com;<br />
</span><span style="color: #008080">&nbsp;2</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
</span><span style="color: #008080">&nbsp;3</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #0000ff">import</span><span style="color: #000000">&nbsp;java.io.Serializabel;<br />
</span><span style="color: #008080">&nbsp;4</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><br />
</span><span style="color: #008080">&nbsp;5</span><span style="color: #000000"><img id="Codehighlighter1_91_282_Open_Image" onclick="this.style.display='none'; Codehighlighter1_91_282_Open_Text.style.display='none'; Codehighlighter1_91_282_Closed_Image.style.display='inline'; Codehighlighter1_91_282_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_91_282_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_91_282_Closed_Text.style.display='none'; Codehighlighter1_91_282_Open_Image.style.display='inline'; Codehighlighter1_91_282_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"  alt="" /></span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">&nbsp;HomeAddress&nbsp;</span><span style="color: #0000ff">implements</span><span style="color: #000000">&nbsp;Serializable</span><span id="Codehighlighter1_91_282_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_91_282_Open_Text"><span style="color: #000000">{<br />
</span><span style="color: #008080">&nbsp;6</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;String&nbsp;street;<br />
</span><span style="color: #008080">&nbsp;7</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;String&nbsp;city;<br />
</span><span style="color: #008080">&nbsp;8</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />
</span><span style="color: #008080">&nbsp;9</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">private</span><span style="color: #000000">&nbsp;com.Customer&nbsp;customer;<br />
</span><span style="color: #008080">10</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />
</span><span style="color: #008080">11</span><span style="color: #000000"><img id="Codehighlighter1_236_240_Open_Image" onclick="this.style.display='none'; Codehighlighter1_236_240_Open_Text.style.display='none'; Codehighlighter1_236_240_Closed_Image.style.display='inline'; Codehighlighter1_236_240_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_236_240_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_236_240_Closed_Text.style.display='none'; Codehighlighter1_236_240_Open_Image.style.display='inline'; Codehighlighter1_236_240_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;setCustomer(Customer&nbsp;customer)</span><span id="Codehighlighter1_236_240_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_236_240_Open_Text"><span style="color: #000000">{<img src="http://www.blogjava.net/Images/dot.gif"  alt="" />}</span></span><span style="color: #000000"><br />
</span><span style="color: #008080">12</span><span style="color: #000000"><img id="Codehighlighter1_277_281_Open_Image" onclick="this.style.display='none'; Codehighlighter1_277_281_Open_Text.style.display='none'; Codehighlighter1_277_281_Closed_Image.style.display='inline'; Codehighlighter1_277_281_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"  alt="" /><img id="Codehighlighter1_277_281_Closed_Image" style="display: none" onclick="this.style.display='none'; Codehighlighter1_277_281_Closed_Text.style.display='none'; Codehighlighter1_277_281_Open_Image.style.display='inline'; Codehighlighter1_277_281_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;Customer&nbsp;getCustomer()</span><span id="Codehighlighter1_277_281_Closed_Text" style="border-right: #808080 1px solid; border-top: #808080 1px solid; display: none; border-left: #808080 1px solid; border-bottom: #808080 1px solid; background-color: #ffffff"><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span id="Codehighlighter1_277_281_Open_Text"><span style="color: #000000">{<img src="http://www.blogjava.net/Images/dot.gif"  alt="" />}</span></span></div>
<br />
hibernate提供的这种组成关系映射允许嵌套使用<br />
<div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"><span style="color: #008080">1</span><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /><span style="color: #000000">&lt;</span><span style="color: #000000">component</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #008080">2</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;</span><span style="color: #000000">&lt;</span><span style="color: #000000">compoent</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #008080">3</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />
</span><span style="color: #008080">4</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;</span><span style="color: #000000">&lt;/</span><span style="color: #000000">componet</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />
</span><span style="color: #008080">5</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" />&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />
</span><span style="color: #008080">6</span><span style="color: #000000"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"  alt="" /></span><span style="color: #000000">&lt;/</span><span style="color: #000000">component</span><span style="color: #000000">&gt;</span></div>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;2. 区分值value类型和实体Entity类型<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Hibernate把持久化类的属性分为value和Entity类型。前者没有OID，不能被单独持久化，不能单独通过session加载，它的生命周期依赖于所属的持久化类的对象生命周期，组件类型就是一种类型；而后者有OID，可以被单独持久化。在通过Configuration类的addClass（）方法加载映射文件时，只需要加载与value类型对应的实体类型，而不需要单独加载组件类。当通过hibernate进行数据库操作的时候，hibernate会自动把组件类的属性转换为实体类的属性，从而和table的列对应起来</span>
<img src ="http://www.blogjava.net/Ericzhang5231/aggbug/177362.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ericzhang5231/" target="_blank">Eric5231</a> 2008-01-23 20:47 <a href="http://www.blogjava.net/Ericzhang5231/articles/AggregationRelation.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第六章 映射对象标识符</title><link>http://www.blogjava.net/Ericzhang5231/articles/OID.html</link><dc:creator>Eric5231</dc:creator><author>Eric5231</author><pubDate>Mon, 21 Jan 2008 13:45:00 GMT</pubDate><guid>http://www.blogjava.net/Ericzhang5231/articles/OID.html</guid><wfw:comment>http://www.blogjava.net/Ericzhang5231/comments/176846.html</wfw:comment><comments>http://www.blogjava.net/Ericzhang5231/articles/OID.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ericzhang5231/comments/commentRss/176846.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ericzhang5231/services/trackbacks/176846.html</trackback:ping><description><![CDATA[<table cellspacing="2" cellpadding="2" width="500" border="0">
    <tbody>
        <tr>
            <td>标识符生成器&nbsp;</td>
            <td>描述</td>
            <td>备注</td>
        </tr>
        <tr>
            <td>increment</td>
            <td>由hibernate通过计算max（ID）来获得标识符，并自动以递增的方式增长</td>
            <td>只适用于单个hibernate应用进程访问同一个数据库场合，在集群环境下不推荐</td>
        </tr>
        <tr>
            <td>identity&nbsp;&nbsp;&nbsp;</td>
            <td>有底层数据库自动增长支持，因此必须是底层数据库支持的自动增长类型</td>
            <td>long，int，short</td>
        </tr>
        <tr>
            <td>sequence&nbsp;&nbsp;</td>
            <td>根据底层数据库的序列来生成标识符</td>
            <td>long，int，short</td>
        </tr>
        <tr>
            <td>hilo&nbsp;&nbsp;</td>
            <td>根据high/low算法来生成标识符</td>
            <td>long，int，short</td>
        </tr>
        <tr>
            <td>native</td>
            <td>根据底层数据库对自动生成标识符的支持能力来选择identity，sequenece或hilo</td>
            <td>long，int，short</td>
        </tr>
        <tr>
            <td>uuid.hex&nbsp;&nbsp;</td>
            <td>采用128位的UUID生成在网络环境下唯一的字符串标识符，单占空间比较多</td>
            <td>long，int，short</td>
        </tr>
        <tr>
            <td>assigned</td>
            <td>由java程序负责生成标识符</td>
            <td>long，int，short</td>
        </tr>
    </tbody>
</table>
 <img src ="http://www.blogjava.net/Ericzhang5231/aggbug/176846.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ericzhang5231/" target="_blank">Eric5231</a> 2008-01-21 21:45 <a href="http://www.blogjava.net/Ericzhang5231/articles/OID.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>第七章 持久化对象</title><link>http://www.blogjava.net/Ericzhang5231/articles/persistentObject.html</link><dc:creator>Eric5231</dc:creator><author>Eric5231</author><pubDate>Mon, 21 Jan 2008 13:25:00 GMT</pubDate><guid>http://www.blogjava.net/Ericzhang5231/articles/persistentObject.html</guid><wfw:comment>http://www.blogjava.net/Ericzhang5231/comments/176842.html</wfw:comment><comments>http://www.blogjava.net/Ericzhang5231/articles/persistentObject.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ericzhang5231/comments/commentRss/176842.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ericzhang5231/services/trackbacks/176842.html</trackback:ping><description><![CDATA[<br />
&lt;p&gt;1）与Java对象在JVM中的生命周期类似，Java对象在Hibernate的session中也有生命周期类似的状态。在Hibernate的session中，对象有3种状态：临时状态，持久化状态，游离状态。&lt;br /&gt;<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;a. 临时状态（transient），刚new出来的对象，还没有被session持久化，不处于session的缓存中&lt;br /&gt;<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; b.持久化状态（persistent），已经被持久化（在数据库中有相应的记录），并且存在于session的缓存中&lt;br /&gt;<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; c. 游离状态（detached），已经被持久化（在数据库中可能存在也可能不存在相应的记录），不存在于session的缓存中&lt;br /&gt;<br />
&lt;br /&gt;<br />
简单的用个例子描述一下：&lt;br /&gt;<br />
&lt;/p&gt;<br />
&lt;div style="border-right: #cccccc 1px solid; padding-right: 5px; border-top: #cccccc 1px solid; padding-left: 4px; font-size: 13px; padding-bottom: 4px; border-left: #cccccc 1px solid; width: 98%; word-break: break-all; padding-top: 4px; border-bottom: #cccccc 1px solid; background-color: #eeeeee"&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;1&lt;/span&gt;&lt;img alt="" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /&gt;&lt;span style="color: #000000"&gt;&lt;img alt="" src="http://www.blogjava.net/Images/dot.gif" /&gt;&lt;br /&gt;<br />
&lt;/span&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;2&lt;/span&gt;&lt;span style="color: #000000"&gt;&lt;img alt="" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /&gt;tx&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;session.beginTransaction();&lt;br /&gt;<br />
&lt;/span&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;3&lt;/span&gt;&lt;span style="color: #000000"&gt;&lt;img alt="" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /&gt;Customer&amp;nbsp;c1&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;new&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;Customer(&lt;/span&gt;&lt;span style="color: #000000"&gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;Tom&lt;/span&gt;&lt;span style="color: #000000"&gt;"&lt;/span&gt;&lt;span style="color: #000000"&gt;,&lt;/span&gt;&lt;span style="color: #0000ff"&gt;new&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;HashSet());&amp;nbsp;&amp;nbsp;&amp;nbsp; //c1 处于临时状态&lt;br /&gt;<br />
&lt;/span&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;4&lt;/span&gt;&lt;span style="color: #000000"&gt;&lt;img alt="" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /&gt;session.save(c1);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//c1转换为持久化状态&lt;br /&gt;<br />
&lt;/span&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;5&lt;/span&gt;&lt;span style="color: #000000"&gt;&lt;img alt="" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /&gt;Long&amp;nbsp;id&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;c1.getId();&lt;br /&gt;<br />
&lt;/span&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;6&lt;/span&gt;&lt;span style="color: #000000"&gt;&lt;img alt="" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /&gt;c1&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;&lt;span style="color: #000000"&gt;;&lt;br /&gt;<br />
&lt;/span&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;7&lt;/span&gt;&lt;span style="color: #000000"&gt;&lt;img alt="" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /&gt;Customer&amp;nbsp;c2&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;(Customer)session.load(Customer.&lt;/span&gt;&lt;span style="color: #0000ff"&gt;class&lt;/span&gt;&lt;span style="color: #000000"&gt;,id);&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//c2 处于持久化状态&lt;br /&gt;<br />
&lt;/span&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;8&lt;/span&gt;&lt;span style="color: #000000"&gt;&lt;img alt="" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /&gt;tx.commit();&lt;br /&gt;<br />
&lt;/span&gt;&lt;span style="color: #008080"&gt;&amp;nbsp;9&lt;/span&gt;&lt;span style="color: #000000"&gt;&lt;img alt="" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /&gt;session.close();&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//c1转换为游离状态 &lt;br /&gt;<br />
&lt;/span&gt;&lt;span style="color: #008080"&gt;10&lt;/span&gt;&lt;span style="color: #000000"&gt;&lt;img alt="" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /&gt;c2&amp;nbsp;&lt;/span&gt;&lt;span style="color: #000000"&gt;=&lt;/span&gt;&lt;span style="color: #000000"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #0000ff"&gt;null&lt;/span&gt;&lt;span style="color: #000000"&gt;;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; //c2转换为游离状态&lt;/span&gt;&lt;/div&gt;<br />
&lt;br /&gt;<br />
&lt;br /&gt;<br />
&lt;br /&gt;<br />
2）对象的状态转换&lt;br /&gt;<br />
&lt;img height="277" alt="" src="http://www.blogjava.net/images/blogjava_net/ericzhang5231/StateTransform.jpg" width="398" border="0" /&gt;&lt;br /&gt;<br />
&lt;br /&gt;<br />
&lt;table style="width: 1000px; height: 195px" cellspacing="2" cellpadding="2" width="1000" border="0"&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;tbody&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;状态名称&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;状态特征&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;进入条件&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;备注&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;临时对象&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;1.不存在任何一个session；&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;2.在数据库没有相应的记录；&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;1. 通过new；&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;2.Session通过delete()把持久化对象和游离对象转化为临时对象&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;持久化对象&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;1.总是被一个Session对象关联；&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;2.在数据库有相应的记录；&lt;br /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.session清理缓存的时候，会根据持久化对象的属性变化（其实根据快照），来同步更新数据库&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;1.session的save()把临时对象转化持久化对象；&lt;br /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.session的load()或get()返回的对象；&lt;br /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.session的find()返回的对象；&lt;br /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.session的update(),saveOrUpdate()和lock()使游离对象转变为持久化对象；&lt;br /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5.当一个持久化对象关联一个临时对象，当允许级联保存的情况下，临时对象也转化为持久化对象；&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;&amp;nbsp;&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;1.避免多个session实例关联一个Java对象&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;游离对象&amp;nbsp;&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;1.不被session关联；&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;2.游离对象是由持久化对象转化过来的，数据库中可能存在也可能不存在相应的记录；&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;1.session的close()，把缓存中的所有持久化对象都转变为游离对象；&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;2.session的evict()，把缓存中的一个持久化对象删除，使它变成游离状态；&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;1.游离对象和临时对象的区别在于数据库是否存在相应的记录&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/tbody&gt;<br />
&lt;/table&gt;<br />
&lt;br /&gt;<br />
&lt;br /&gt;<br />
&lt;br /&gt;<br />
3)Session的缓存以及API&lt;br /&gt;<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;1.Session：在Session接口的实现类SessionImpl中定义了一系列的Java集合，这些集合构成了Sessiond缓存&lt;br /&gt;<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;2.API：&lt;br /&gt;<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;<br />
&lt;table style="width: 1005px; height: 270px" cellspacing="2" cellpadding="2" width="1005" border="0"&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;tbody&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;save()&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;1.在save一个临时对象之前，设置对象的主键ID，没效果；&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;2.在save一个对象之后，对象主键ID不能修改，否则抛异常；&lt;br /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.如果主键ID是用nactive方式生成的，一旦调用session的save方法，hibernate会立即向数据库插入数据；&lt;br /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.save用来持久化一个临时对象，若持久一个持久化对象，没效果，若持久一个游离对象，会重新插入数据；&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;update()&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;1.session清理缓存的时候，才会去执行update()产生的sql语句，因此即使程序多次修改对象属性，最后只会更新最后的修改；&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;2.通过update()使一个游离对象被一个session关联，即使没有修改对象属性，在清理缓存的时候也会执行update()产生sql语句&lt;br /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; （如果希望仅当修改对象属性才进行update，可在&amp;lt;class&amp;gt;元素的select-before-update设置为true）；&lt;br /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3.当update()方法关联一个游离对象，如果session中存在相同OID的持久化对象，会抛出异常；&lt;br /&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.当update()方法关联一个游离对象，如果数据库中不存在相应记录，会抛出异常；&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;saveOrUpdate()&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;p&gt;1.如果传入的是临时对象，调用save(); 如果传入的是持久化对象，调用update();&lt;/p&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;load(), get()&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;1.两者都是根据OID从数据库中加载持久化对象，区别是：当数据库不存在与OID对应的记录，load()会抛出net.sf.hibernate.ObjectNotFoundException，而get()方法返回null；&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;delete()&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;1.对传入的是持久化对象，session就按照预先的sql语句删除一个记录；如果是一个游离态对象，会把它关联到session，在按照sql语句删除记录&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/tbody&gt;<br />
&lt;/table&gt;<br />
&lt;br /&gt;<br />
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;3.session的级联：因为对象是相互关联，因此在session存放的是一副相互关联的对象图。在对象-关联映射文件中，用于映射持久化类之间关联的元素，如&amp;lt;set&amp;gt;,&amp;lt;many-to-one&amp;gt;,&amp;lt;one-to-many&amp;gt;，都有一个cascade属性。casecade属性值如下：&lt;br /&gt;<br />
&lt;table cellspacing="2" cellpadding="2" width="500" border="0"&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;tbody&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;属性值&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;描述&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;none&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;默认值，忽略关联对象&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;save-update&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;session对当前对象调用save(),update(),saveOrUpdate()，级联保存关联的临时对象，级联更新关联的游离对象&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;delete&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;级联删除所有关联的对象&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;all&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;包含save-update(),delelte()行为；当对当前对象执行evict()或lock()，级联执行关联的对象&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;delete-orphan&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;删除所有和当前对象解除关联关系的对象&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tr&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;all-delete-orphan&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;td&gt;包含all和delete-orphan的行为&lt;/td&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tr&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/tbody&gt;<br />
&lt;/table&gt;<br />
<img src ="http://www.blogjava.net/Ericzhang5231/aggbug/176842.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ericzhang5231/" target="_blank">Eric5231</a> 2008-01-21 21:25 <a href="http://www.blogjava.net/Ericzhang5231/articles/persistentObject.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于hibernate category</title><link>http://www.blogjava.net/Ericzhang5231/articles/hibernate.html</link><dc:creator>Eric5231</dc:creator><author>Eric5231</author><pubDate>Mon, 21 Jan 2008 12:03:00 GMT</pubDate><guid>http://www.blogjava.net/Ericzhang5231/articles/hibernate.html</guid><wfw:comment>http://www.blogjava.net/Ericzhang5231/comments/176821.html</wfw:comment><comments>http://www.blogjava.net/Ericzhang5231/articles/hibernate.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/Ericzhang5231/comments/commentRss/176821.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/Ericzhang5231/services/trackbacks/176821.html</trackback:ping><description><![CDATA[&#8216;只有沉得下去的人，才能浮起来&#8217;<br />
<br />
很久之前因为课程项目的缘故，杂七杂八的学了一段时间hibernate，实操也不多，在pccw实习的那段期间一直虽然接触着hibernate，但是从来都是扮演着木头的角色，没有真正思考过用得对不对，如果不对，又应该怎么去改善或者提高<br />
<br />
这段时间，闲着也闲着，回去pccw是不可能的了，人还是要有自己的原则的，破坏了自己的原则，你在别人心中的形象也会随之而毁的；干脆静下心来，在学习新东西之前，好好重新复习一些东西，好好把孙卫琴的《精通Hibernate》复习一遍<br />
<br />
于是hibernate这个Category应运而生<br />
<img src ="http://www.blogjava.net/Ericzhang5231/aggbug/176821.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/Ericzhang5231/" target="_blank">Eric5231</a> 2008-01-21 20:03 <a href="http://www.blogjava.net/Ericzhang5231/articles/hibernate.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>