﻿<?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-macrochao-文章分类-j2ee(转)</title><link>http://www.blogjava.net/macrochao/category/29351.html</link><description /><language>zh-cn</language><lastBuildDate>Sun, 03 Feb 2008 14:59:03 GMT</lastBuildDate><pubDate>Sun, 03 Feb 2008 14:59:03 GMT</pubDate><ttl>60</ttl><item><title>Hibernate的unsaved-value</title><link>http://www.blogjava.net/macrochao/articles/179208.html</link><dc:creator>macrochao</dc:creator><author>macrochao</author><pubDate>Sun, 03 Feb 2008 09:28:00 GMT</pubDate><guid>http://www.blogjava.net/macrochao/articles/179208.html</guid><wfw:comment>http://www.blogjava.net/macrochao/comments/179208.html</wfw:comment><comments>http://www.blogjava.net/macrochao/articles/179208.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/macrochao/comments/commentRss/179208.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/macrochao/services/trackbacks/179208.html</trackback:ping><description><![CDATA[<span class="postbody">当你显式的使用session.save()或者session.update()操作一个对象的时候，实际上是用不到<span style="color: #ffa34f"><strong>unsaved-value</strong></span>的。某些情况下(父子表关联保存)，当你在程序中并没有显式的使用save或者update一个持久对象，那么Hibernate需要判断被操作的对象究竟是一个已经持久化过的持久对象，是一个尚未被持久化过的内存临时对象。例如： <br />
<br />
</span>
<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td><span class="genmed"><strong><font size="4">java代码: </font></strong></span></td>
        </tr>
        <tr>
            <td class="code">
            <div><br />
            <font size="4">Session session = ...; <br />
            Transaction tx = ...; <br />
            <br />
            Parent parent = <span style="color: #000000">(</span>Parent<span style="color: #000000">)</span> session.<span style="color: #000000">load</span><span style="color: #000000">(</span>Parent.<span style="color: #000000">class</span>, id<span style="color: #000000">)</span>; <br />
            <br />
            Child child = <span style="font-weight: bold; color: #990066">new</span> Child<span style="color: #000000">(</span><span style="color: #000000">)</span>; <br />
            child.<span style="color: #000000">setParent</span><span style="color: #000000">(</span>parent<span style="color: #000000">)</span>; <br />
            child.<span style="color: #000000">setName</span><span style="color: #000000">(</span>"sun"<span style="color: #000000">)</span>; <br />
            <br />
            parent.<span style="color: #000000">addChild</span><span style="color: #000000">(</span>child<span style="color: #000000">)</span>; <br />
            s.<span style="color: #000000">update</span><span style="color: #000000">(</span>parent<span style="color: #000000">)</span>; <br />
            <br />
            s.<span style="color: #000000">flush</span><span style="color: #000000">(</span><span style="color: #000000">)</span>; <br />
            tx.<span style="color: #000000">commit</span><span style="color: #000000">(</span><span style="color: #000000">)</span>; <br />
            s.<span style="color: #000000">close</span><span style="color: #000000">(</span><span style="color: #000000">)</span>;</font></div>
            </td>
        </tr>
    </tbody>
</table>
<span class="postbody"><br />
<br />
在上例中，程序并没有显式的session.save(child); 那么Hibernate需要知道child究竟是一个临时对象，还是已经在数据库中有的持久对象。如果child是一个新创建的临时对象(本例中就是这种情况)，那么Hibernate应该自动产生session.save(child)这样的操作，如果child是已经在数据库中有的持久对象，那么Hibernate应该自动产生session.update(child)这样的操作。 <br />
<br />
因此我们需要暗示一下Hibernate，究竟child对象应该对它自动save还是update。在上例中，显然我们应该暗示Hibernate对child自动save，而不是自动update。那么Hibernate如何判断究竟对child是save还是update呢？它会取一下child的主键属性 child.getId() ，这里假设id是 java.lang.Integer类型的。如果取到的Id值和hbm映射文件中指定的unsave-value相等，那么Hibernate认为child是新的内存临时对象，发送save，如果不相等，那么Hibernate认为child是已经持久过的对象，发送update。 <br />
<br />
<span style="color: #ffa34f"><strong>unsaved-value</strong></span>="null" (默认情况，适用于大多数对象类型主键 Integer/Long/String/...) <br />
<br />
当Hibernate取一下child的Id，取出来的是null(在上例中肯定取出来的是null)，和<span style="color: #ffa34f"><strong>unsaved-value</strong></span>设定值相等，发送save(child) <br />
<br />
当Hibernate取一下child的id，取出来的不是null，那么和<span style="color: #ffa34f"><strong>unsaved-value</strong></span>设定值不相等，发送update(child) <br />
<br />
例如下面的情况： <br />
<br />
</span>
<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td><span class="genmed"><strong>java代码: </strong></span></td>
        </tr>
        <tr>
            <td class="code">
            <div><br />
            <font size="4">Session session = ...; <br />
            Transaction tx = ...; <br />
            <br />
            Parent parent = <span style="color: #000000">(</span>Parent<span style="color: #000000">)</span> session.<span style="color: #000000">load</span><span style="color: #000000">(</span>Parent.<span style="color: #000000">class</span>, id<span style="color: #000000">)</span>; <br />
            Child child = <span style="color: #000000">(</span>Child<span style="color: #000000">)</span> session.<span style="color: #000000">load</span><span style="color: #000000">(</span>Child.<span style="color: #000000">class</span>, childId<span style="color: #000000">)</span>; <br />
            <br />
            child.<span style="color: #000000">setParent</span><span style="color: #000000">(</span>parent<span style="color: #000000">)</span>; <br />
            child.<span style="color: #000000">setName</span><span style="color: #000000">(</span>"sun"<span style="color: #000000">)</span>; <br />
            <br />
            parent.<span style="color: #000000">addChild</span><span style="color: #000000">(</span>child<span style="color: #000000">)</span>; <br />
            s.<span style="color: #000000">update</span><span style="color: #000000">(</span>parent<span style="color: #000000">)</span>; <br />
            <br />
            s.<span style="color: #000000">flush</span><span style="color: #000000">(</span><span style="color: #000000">)</span>; <br />
            tx.<span style="color: #000000">commit</span><span style="color: #000000">(</span><span style="color: #000000">)</span>; <br />
            s.<span style="color: #000000">close</span><span style="color: #000000">(</span><span style="color: #000000">)</span>;</font></div>
            </td>
        </tr>
    </tbody>
</table>
<span class="postbody"><br />
<br />
child已经在数据库中有了，是一个持久化的对象，不是新创建的，因此我们希望Hibernate发送update(child)，在该例中，Hibernate取一下child.getId()，和unsave-value指定的null比对一下，发现不相等，那么发送update(child)。 <br />
<br />
BTW: parent对象不需要操心，因为程序显式的对parent有load操作和update的操作，不需要Hibernate自己来判断究竟是save还是update了。我们要注意的只是child对象的操作。另外<span style="color: #ffa34f"><strong>unsaved-value</strong></span>是定义在Child类的主键属性中的。 <br />
<br />
</span>
<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td><span class="genmed"><strong>java代码: </strong></span></td>
        </tr>
        <tr>
            <td class="code">
            <div><br />
            <font size="4">&lt;<span style="font-weight: bold; color: #990066">class</span> name="Child" table="child"&gt; <br />
            &lt;id column="id" name="id" type="integer" <span style="color: #ffa34f"><strong>unsaved-value</strong></span>="<span style="font-weight: bold; color: #990066">null</span>"&gt; <br />
            &lt;generator <span style="font-weight: bold; color: #990066">class</span>="identity"/&gt; <br />
            &lt;/id&gt; <br />
            ... <br />
            &lt;/<span style="font-weight: bold; color: #990066">class</span>&gt;</font></div>
            </td>
        </tr>
    </tbody>
</table>
<span class="postbody"><br />
<br />
如果主键属性不是对象型，而是基本类型，如int/long/double/...，那么你需要指定一个数值型的<span style="color: #ffa34f"><strong>unsaved-value</strong></span>，例如： <br />
<br />
</span>
<table cellspacing="1" cellpadding="3" width="90%" align="center" border="0">
    <tbody>
        <tr>
            <td><span class="genmed"><strong>java代码: </strong></span></td>
        </tr>
        <tr>
            <td class="code">
            <div><br />
            unsaved-<span style="font-weight: bold; color: #990066">null</span>="<span style="color: #000000">0</span>"</div>
            </td>
        </tr>
    </tbody>
</table>
<span class="postbody"><br />
<br />
在此提醒大家，很多人以为对主键属性定义为int/long，比定义为Integer/Long运行效率来得高，认为基本类型不需要进行对象的封装和解构操作，因此喜欢把主键定义为int/long的。但实际上，Hibernate内部总是把主键转换为对象型进行操作的，就算你定义为int/long型的，Hibernate内部也要进行一次对象构造操作，返回给你的时候，还要进行解构操作，效率可能反而低也说不定。因此大家一定要扭转一个观点，在Hibernate中，主键属性定义为基本类型，并不能够比定义为对象型效率来的高，而且也多了很多麻烦，因此建议大家使用对象型的Integer/Long定义主键。 <br />
<br />
<span style="color: #ffa34f"><strong>unsaved-value</strong></span>="none"和 <br />
<span style="color: #ffa34f"><strong>unsaved-value</strong></span>="any" <br />
<br />
主主要用在主键属性不是通过Hibernate生成，而是程序自己setId()的时候。 <br />
<br />
在这里多说一句，强烈建议使用Hibernate的id generator，或者你可以自己扩展Hibernate的id generator，特别注意不要使用有实际含义的字段当做主键来用！例如用户类User，很多人喜欢用用户登陆名称做为主键，这是一个很不好的习惯，当用户类和其他实体类有关联关系的时候，万一你需要修改用户登陆名称，一改就需要改好几张表中的数据。偶合性太高，而如果你使用无业务意义的id generator，那么修改用户名称，就只修改user表就行了。 <br />
<br />
由这个问题引申出来，如果你严格按照这个原则来设计数据库，那么你基本上是用不到手工来setId()的，你用Hibernate的id generator就OK了。因此你也不需要了解当 <br />
<br />
<span style="color: #ffa34f"><strong>unsaved-value</strong></span>="none"和 <br />
<span style="color: #ffa34f"><strong>unsaved-value</strong></span>="any" <br />
<br />
究竟有什么含义了。如果你非要用assigned不可，那么继续解释一下： <br />
<br />
<span style="color: #ffa34f"><strong>unsaved-value</strong></span>="none" 的时候，由于不论主键属性为任何值，都不可能为none，因此Hibernate总是对child对象发送update(child) <br />
<br />
<span style="color: #ffa34f"><strong>unsaved-value</strong></span>="any" 的时候，由于不论主键属性为任何值，都肯定为any，因此Hibernate总是对child对象发送save(child) <br />
<br />
大多数情况下，你可以避免使用assigned，只有当你使用复合主键的时候不得不手工setId()，这时候需要你自己考虑究竟怎么设置<span style="color: #ffa34f"><strong>unsaved-value</strong></span>了，根据你自己的需要来定。 <br />
<br />
BTW: Gavin King强烈不建议使用composite-id，强烈建议使用UserType。 <br />
<br />
因此，如果你在系统设计的时候，遵循如下原则： <br />
<br />
<span style="color: red">1、使用Hibernate的id generator来生成无业务意义的主键，不使用有业务含义的字段做主键，不使用assigned。 <br />
<br />
2、使用对象类型(String/Integer/Long/...)来做主键，而不使用基础类型(int/long/...)做主键 <br />
<br />
3、不使用composite-id来处理复合主键的情况，而使用UserType来处理该种情况。</span> <br />
<br />
那么你永远用的是<span style="color: #ffa34f"><strong>unsaved-value</strong></span>="null" ，不可能用到any/none/..了。</span><br />
 <img src ="http://www.blogjava.net/macrochao/aggbug/179208.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/macrochao/" target="_blank">macrochao</a> 2008-02-03 17:28 <a href="http://www.blogjava.net/macrochao/articles/179208.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>