﻿<?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-疯狂 --专注java,开源,架构,项目管理-随笔分类-hibernate</title><link>http://www.blogjava.net/freeman1984/category/42534.html</link><description>         
        STANDING ON THE SHOULDERS OF GIANTS</description><language>zh-cn</language><lastBuildDate>Fri, 25 Nov 2011 09:16:46 GMT</lastBuildDate><pubDate>Fri, 25 Nov 2011 09:16:46 GMT</pubDate><ttl>60</ttl><item><title>hibernate，spring管理事务中(transaction，JDBC connection，Hibernate Session的使用研究)（一）</title><link>http://www.blogjava.net/freeman1984/archive/2011/11/18/363984.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 18 Nov 2011 03:25:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/11/18/363984.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/363984.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/11/18/363984.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/363984.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/363984.html</trackback:ping><description><![CDATA[如果单独使用hibernate可参考上一篇文章<a href="http://www.blogjava.net/freeman1984/archive/2011/08/04/355808.html">http://www.blogjava.net/freeman1984/archive/2011/08/04/355808.html</a><br /><br /><strong>首先hibernate的Connection release mode有以下几种：<br /></strong>1 after_statement 2 after_transaction 3 on_close 其中after_statement 用在jta中 ，<span style="color: red"><strong>on_close 是3.1之前遗留的（也许是为spring留的-_-），也就是3.1之前默认是on_close ，但3.1之后默认如果单独使用hibernate是after_transaction，</strong></span>如果有第三方事务管理，就用第三方提供的默认值，spring就是默认使用了on_close。<br /><strong>在spring管理事务中我们看看系统启动后默认使用的配置：<br /></strong>1,ransaction strategy: org.springframework.orm.hibernate3.SpringTransactionFactory使用spring事务策略<br />2，hibernate内部 Automatic session close at end of transaction: disabled 因为已经交给spring了<br />3&nbsp;&nbsp; Connection release mode: auto 默认，也就是没有配置hibernate.connection.release_mode的时候，但是这里有地方需要注意：也就是前面提到的使用第三方策略时的问题：看一下代码： 
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" /><span style="color: #000000">String&nbsp;releaseModeName&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;PropertiesHelper.getString(&nbsp;Environment.RELEASE_CONNECTIONS,&nbsp;properties,&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">auto</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;);<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.info(&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">Connection&nbsp;release&nbsp;mode:&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">+</span><span style="color: #000000">&nbsp;releaseModeName&nbsp;);<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConnectionReleaseMode&nbsp;releaseMode;<br /><img id="Codehighlighter1_246_311_Open_Image" onclick="this.style.display='none'; Codehighlighter1_246_311_Open_Text.style.display='none'; Codehighlighter1_246_311_Closed_Image.style.display='inline'; Codehighlighter1_246_311_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_246_311_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_246_311_Closed_Text.style.display='none'; Codehighlighter1_246_311_Open_Image.style.display='inline'; Codehighlighter1_246_311_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">auto</span><span style="color: #000000">"</span><span style="color: #000000">.equals(releaseModeName)&nbsp;)&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_246_311_Closed_Text"><img alt="" src="http://www.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_246_311_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: red">releaseMode&nbsp;</span><span style="color: red">=</span><span style="color: red">&nbsp;transactionFactory.getDefaultReleaseMode();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" /></span></span><span style="color: #000000"><br /><img id="Codehighlighter1_320_663_Open_Image" onclick="this.style.display='none'; Codehighlighter1_320_663_Open_Text.style.display='none'; Codehighlighter1_320_663_Closed_Image.style.display='inline'; Codehighlighter1_320_663_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_320_663_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_320_663_Closed_Text.style.display='none'; Codehighlighter1_320_663_Open_Image.style.display='inline'; Codehighlighter1_320_663_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">else</span><span style="color: #000000">&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_320_663_Closed_Text"><img alt="" src="http://www.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_320_663_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;releaseMode&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;ConnectionReleaseMode.parse(&nbsp;releaseModeName&nbsp;);<br /><img id="Codehighlighter1_494_659_Open_Image" onclick="this.style.display='none'; Codehighlighter1_494_659_Open_Text.style.display='none'; Codehighlighter1_494_659_Closed_Image.style.display='inline'; Codehighlighter1_494_659_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif"><img style="display: none" id="Codehighlighter1_494_659_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_494_659_Closed_Text.style.display='none'; Codehighlighter1_494_659_Open_Image.style.display='inline'; Codehighlighter1_494_659_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">if</span><span style="color: #000000">&nbsp;(&nbsp;releaseMode&nbsp;</span><span style="color: #000000">==</span><span style="color: #000000">&nbsp;ConnectionReleaseMode.AFTER_STATEMENT&nbsp;</span><span style="color: #000000">&amp;&amp;</span><span style="color: #000000">&nbsp;</span><span style="color: #000000">!</span><span style="color: #000000">connections.supportsAggressiveRelease()&nbsp;)&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_494_659_Closed_Text"><img alt="" src="http://www.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_494_659_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log.warn(&nbsp;</span><span style="color: #000000">"</span><span style="color: #000000">Overriding&nbsp;release&nbsp;mode&nbsp;as&nbsp;connection&nbsp;provider&nbsp;does&nbsp;not&nbsp;support&nbsp;'after_statement'</span><span style="color: #000000">"</span><span style="color: #000000">&nbsp;);<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;releaseMode&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;ConnectionReleaseMode.AFTER_TRANSACTION;<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span></span></div>其中红色部分就是调用了spring提供的默认值，而spring的默认值：在jta和cmt中都默认使用的是after_statement<br />
<div style="border-bottom: #cccccc 1px solid; border-left: #cccccc 1px solid; padding-bottom: 4px; background-color: #eeeeee; padding-left: 4px; width: 98%; padding-right: 5px; font-size: 13px; word-break: break-all; border-top: #cccccc 1px solid; border-right: #cccccc 1px solid; padding-top: 4px"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><img id="Codehighlighter1_0_328_Open_Image" onclick="this.style.display='none'; Codehighlighter1_0_328_Open_Text.style.display='none'; Codehighlighter1_0_328_Closed_Image.style.display='inline'; Codehighlighter1_0_328_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_0_328_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_0_328_Closed_Text.style.display='none'; Codehighlighter1_0_328_Open_Image.style.display='inline'; Codehighlighter1_0_328_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif"><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_0_328_Closed_Text">/**&nbsp;*/</span><span id="Codehighlighter1_0_328_Open_Text"><span style="color: #008000">/**</span><span style="color: #008000"><br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Sets&nbsp;connection&nbsp;release&nbsp;mode&nbsp;"on_close"&nbsp;as&nbsp;default.<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&lt;p&gt;This&nbsp;was&nbsp;the&nbsp;case&nbsp;for&nbsp;Hibernate&nbsp;3.0;&nbsp;Hibernate&nbsp;3.1&nbsp;changed<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;it&nbsp;to&nbsp;"auto"&nbsp;(i.e.&nbsp;"after_statement"&nbsp;or&nbsp;"after_transaction").<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;However,&nbsp;for&nbsp;Spring's&nbsp;resource&nbsp;management&nbsp;(in&nbsp;particular&nbsp;for<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;HibernateTransactionManager),&nbsp;"on_close"&nbsp;is&nbsp;the&nbsp;better&nbsp;default.<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000">*/</span></span><span style="color: #000000"><br /><img id="Codehighlighter1_384_428_Open_Image" onclick="this.style.display='none'; Codehighlighter1_384_428_Open_Text.style.display='none'; Codehighlighter1_384_428_Closed_Image.style.display='inline'; Codehighlighter1_384_428_Closed_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif"><img style="display: none" id="Codehighlighter1_384_428_Closed_Image" onclick="this.style.display='none'; Codehighlighter1_384_428_Closed_Text.style.display='none'; Codehighlighter1_384_428_Open_Image.style.display='inline'; Codehighlighter1_384_428_Open_Text.style.display='inline';" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;ConnectionReleaseMode&nbsp;getDefaultReleaseMode()&nbsp;</span><span style="border-bottom: #808080 1px solid; border-left: #808080 1px solid; background-color: #ffffff; display: none; border-top: #808080 1px solid; border-right: #808080 1px solid" id="Codehighlighter1_384_428_Closed_Text"><img alt="" src="http://www.blogjava.net/Images/dot.gif" /></span><span id="Codehighlighter1_384_428_Open_Text"><span style="color: #000000">{<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">return</span><span style="color: #000000">&nbsp;ConnectionReleaseMode.ON_CLOSE;<br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" />&nbsp;&nbsp;&nbsp;&nbsp;}</span></span><span style="color: #000000"><br /><img alt="" align="top" src="http://www.blogjava.net/images/OutliningIndicators/None.gif" /></span></div><br />而spring为什么要使用on_close ，而不是用after_transaction ,我们想想opensessioninview的原理也许能明白，session在view成还要使用，所以不能再transactio<span>n使用完后关闭JDBC connection，必须要在session之后，所以要使用on<strong>_close</strong></span><strong><span>（</span><span>也就是在on session(flush.auto，或者flush.Eagerly) 关闭）。这种情况hibernate内部还会在spring关闭JDBC connection后提示(费解，因为after transaction之后session没有关闭，但是&nbsp;Connection release mode配置的是on_close,session的关闭和&nbsp;Connection 的关闭都由spring来管理，hibernate就不知道了)，所以hibernate有好的提示如下(其实session，已经关闭。当然随着session的关闭jdbc链接释放回连接池)：</span><br /><span style="color: red">transaction completed on session with on_close connection release mode; be sure to cl</span></strong>ose the session to release JDBC resources!，<br /><br />。当然我们也可以使用after_transaction ，这种情况对使用编程式事务非常适用。<br />&nbsp;&nbsp;&nbsp;&nbsp;   <img src ="http://www.blogjava.net/freeman1984/aggbug/363984.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-11-18 11:25 <a href="http://www.blogjava.net/freeman1984/archive/2011/11/18/363984.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>mappedBy跟JoinColumn/JoinTable .</title><link>http://www.blogjava.net/freeman1984/archive/2011/09/30/359857.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Fri, 30 Sep 2011 06:28:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/09/30/359857.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/359857.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/09/30/359857.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/359857.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/359857.html</trackback:ping><description><![CDATA[<p>对于mappedBy复习下：</p>
<p>a) 只有OneToOne,OneToMany,ManyToMany上才有mappedBy属性，ManyToOne不存在该属性； <br />b) mappedBy标签一定是定义在the owned side(被拥有方的)，他指向the owning side(拥有方)；<br />c) mappedBy的含义，应该理解为，拥有方能够自动维护 跟被拥有方的关系； <br />&nbsp;&nbsp; 当然，如果从被拥有方，通过手工强行来维护拥有方的关系也是可以做到的。</p>
<p>d) mappedBy跟JoinColumn/JoinTable总是处于互斥的一方，可以理解为正是由于拥有方的关联被拥有方的字段存在，拥有方才拥有了被 拥有方。mappedBy这方定义的JoinColumn/JoinTable总是失效的，不会建立对应的字段或者表 </p>
<p>&nbsp;</p>
<p><br />人跟身份证双向关联</p>
<p>在Person 里面定义的注解：</p>
<p>@OneToOne(cascade={CascadeType.ALL},optional=true) <br />public IDCard getIdCard() { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return idCard; <br />}</p>
<p>在IDCard 里面定义的注释: <br />@OneToOne(cascade=CascadeType.ALL,mappedBy="idCard" , optional=false) <br />public Person getPerson() { <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return person; <br />} <br />多了一个mappedBy这个方法,它表示什么呢?它表示当前所在表和Person的关系是定义在Person里面的idCard这个成员上面的,它表示此表是一对一关系中的从表,也就是关系是在person表里面维护的 ,这一点很重要 . Person表是关系的维护者，owner side，有主导权，它有个外键指向IDCard。 <br />我们也可以让主导权在IDCard上面,也就是让它产生一个指向Person的外键,这也是可以的,但是最好是让Person来维护整个关系,这样更符合我们正常的思维 . </p>
<p>我们也可以看到在Person里面IDCard是注释是optional=true,也就是说一个人是可以没有身份证的,但是一个身份证不可以没有人,所以在IDCard里面注释person的时候,optional就为false了,这样就可以防止一个空的身份证记录进数据库.</p><img src ="http://www.blogjava.net/freeman1984/aggbug/359857.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-09-30 14:28 <a href="http://www.blogjava.net/freeman1984/archive/2011/09/30/359857.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用hibernate中connection.release_mode，connection.autocommit和transaction.auto_close_session用法及需要注意的问题</title><link>http://www.blogjava.net/freeman1984/archive/2011/08/04/355808.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 04 Aug 2011 07:57:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/08/04/355808.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/355808.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/08/04/355808.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/355808.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/355808.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: connection.release_mode，connection.autocommit和transaction.auto_close_session用法 <br>&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/08/04/355808.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/355808.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-08-04 15:57 <a href="http://www.blogjava.net/freeman1984/archive/2011/08/04/355808.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于Hibernate读取select count(*)的返回值到底是Long还是Integer的疑惑（转载）</title><link>http://www.blogjava.net/freeman1984/archive/2011/07/27/355166.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Wed, 27 Jul 2011 09:31:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/07/27/355166.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/355166.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/07/27/355166.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/355166.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/355166.html</trackback:ping><description><![CDATA[我这里把代码贴一下： <br />&nbsp;&nbsp;<br />Java co<wbr>de<font color="#000">&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;</font><font color="#00ff">public</font><br /><font color="#00ff">int</font><font color="#000"> countAllSubject() {<br />&nbsp; &nbsp; Session session </font><font color="#000">=</font><font color="#000"> HibernateUtil.getSessionFactory().getCurrentSession();<br />&nbsp; &nbsp; session.beginTransaction();<br />&nbsp; &nbsp; </font><font color="#00ff">return</font><font color="#000"> ((Long) session.createQuery(<br />&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;</font><font color="#000">"</font><font color="#000">select count(*) from Post where idParent=0</font><font color="#000">"</font><font color="#000">).iterate().next())<br />&nbsp; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;.intValue();<br />&nbsp;&nbsp;}</font><br /><br /><br />&nbsp;&nbsp;<br />在我的机器上，用Long作为返回值，运行正常，如果改成Integer，则报如下错误 <br />Java co<wbr>de<font color="#000">type Exception report<br /><br />message<br /><br />description The server encountered an internal error () that prevented it from fulfilling&nbsp;&nbsp;&nbsp; this </font><font color="#000">request.<br /><br />exception<br /><br />org.apache.jasper.JasperException: java.lang.ClassCastException: <strong>java.lang.Long cannot be cast to java.lang.Integer<br /></strong>&nbsp; &nbsp; org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:</font><font color="#000">522</font><font color="#000">)<br />&nbsp; &nbsp; org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:</font><font color="#000">416</font><font color="#000">)<br />&nbsp; &nbsp; org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:</font><font color="#000">337</font><font color="#000">)<br />&nbsp; &nbsp; org.apache.jasper.servlet.JspServlet.service(JspServlet.java:</font><font color="#000">266</font><font color="#000">)<br />&nbsp; &nbsp; javax.servlet.http.HttpServlet.service(HttpServlet.java:</font><font color="#000">803</font><font color="#000">)<br /><br />root cause<br /><br />java.lang.ClassCastException: <strong>java.lang.Long cannot be cast to java.lang.Integer<br /></strong>&nbsp; &nbsp; net.java2000.notepad.service.impl.hibernate.PostServiceHibernateImpl.countAllSubject(PostServiceHibernateImpl.java:</font><font color="#000">24</font><font color="#000">)<br />&nbsp; &nbsp; org.apache.jsp.jsph.index_jsp._jspService(index_jsp.java:</font><font color="#000">93</font><font color="#000">)<br />&nbsp; &nbsp; org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:</font><font color="#000">70</font><font color="#000">)<br />&nbsp; &nbsp; javax.servlet.http.HttpServlet.service(HttpServlet.java:</font><font color="#000">803</font><font color="#000">)<br />&nbsp; &nbsp; org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:</font><font color="#000">374</font><font color="#000">)<br />&nbsp; &nbsp; org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:</font><font color="#000">337</font><font color="#000">)<br />&nbsp; &nbsp; org.apache.jasper.servlet.JspServlet.service(JspServlet.java:</font><font color="#000">266</font><font color="#000">)<br />&nbsp; &nbsp; javax.servlet.http.HttpServlet.service(HttpServlet.java:</font><font color="#000">803</font><font color="#000">)<br /><br />note The full stack trace of the root cause is available in the Apache Tomcat</font><font color="#000">/</font><font color="#000">6.0</font><font color="#000">.</font><font color="#000">16</font><font color="#000"> logs.</font><br /><br /><br />&nbsp;&nbsp;<br />&nbsp;&nbsp;<br />但是，有几个网友却是正好相反，他们直接运行报 <br />&nbsp;&nbsp;<br />java.lang.ClassCastException: <strong>java.lang.Integer&nbsp;&nbsp;<br /></strong>&nbsp;&nbsp;<br />改成Integer却正常了。 <br />&nbsp;&nbsp;<br />&nbsp;&nbsp;<br />希望大家使用Hibernate比较熟悉的人，确认一下，大家随意使用 count(*) 然后读取看看，到底是Integer,还是 Long <br /><br /><br /><br />解决方案：<br />关于在Hibernate里使用select count(*) 返回值的问题说明 <br />由于我使用的是Hibernate 3.2版本，经确认，这个版本已经把以前返回 Integer的改成了 Long, <br />因为JPA里面的返回值规定是Long, Hibernate为了兼容这个，所以修改了返回值。 <br />&nbsp;&nbsp;<br />如果你从Hibernate 3.0.x/3.1.x升级到最新的3.2版，一定要注意，3.2版的很多sql函数如count(), sum()的唯一返回值已经从Integer变为Long，如果不升级代码，会得到一个ClassCastException。 <br />&nbsp;&nbsp;<br />这个变化主要是为了兼容JPA，可以在hibernate.org的最新文档中找到说明。 <br />&nbsp;&nbsp;<br />Hibernate Team也提供了一个与原来兼容的解决方案： <br />&nbsp;&nbsp;<br />&nbsp; &nbsp;Configuration classicCfg = new Configuration(); <br />&nbsp; &nbsp;classicCfg.addSqlFunction( "count", new ClassicCountFunction()); <br />&nbsp; &nbsp;classicCfg.addSqlFunction( "avg", new ClassicAvgFunction()); <br />&nbsp; &nbsp;classicCfg.addSqlFunction( "sum", new ClassicSumFunction()); <br />&nbsp; &nbsp;SessionFactory classicSf = classicCfg.buildSessionFactory(); <br />当然最好统一转换成Number然后获取 <img src ="http://www.blogjava.net/freeman1984/aggbug/355166.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-07-27 17:31 <a href="http://www.blogjava.net/freeman1984/archive/2011/07/27/355166.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>connection.release_mode</title><link>http://www.blogjava.net/freeman1984/archive/2011/07/27/355110.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Wed, 27 Jul 2011 03:15:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/07/27/355110.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/355110.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/07/27/355110.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/355110.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/355110.html</trackback:ping><description><![CDATA[<div id="blog_text" class="cnt">
<div>
<p>org.hibernate.connection包的主要封装了通过JDBC来连接数据库的操作，用户可以以数据源的方式，或者通过特定数据库驱动的方式，甚至是自己定义连接类的方式来完成数据库的连接操作，包下面的代码文件并不多，只有5个，分别是ConnectionProviderFactory.java，ConnectionProvider.java，DriverManagerConnectionProvider.java，DatasourceConnectionProvider.java，UserSuppliedConnectionProvider.java，其中ConnectionProvider是一个接口,DriverManagerConnectionProvider、DatasourceConnectionProvider、UserSuppliedConnectionProvider分别继承了这个接口，而ConnectionProviderFactory则是一个工厂类，他的主要作用是调用ConnectionProvider接口，而不关心接口的具体实现是DriverManagerConnectionProvider或者DatasourceConnectionProvider还是UserSuppliedConnectionProvider。 </p>
<p>&nbsp;&nbsp;&nbsp; 首先来看ConnectionProvider接口，提供了如下几个方法： &nbsp;&nbsp;&nbsp;</p>
<p>1.configure()方法主要是根据配置文件来初始化所有的连接信息。 &nbsp;&nbsp;&nbsp;</p>
<p>2.getConnection()方法抓取一个连接。 &nbsp;&nbsp;&nbsp;</p>
<p>3.closeConnection(Connection conn)方法关闭某个特定连接。 &nbsp;&nbsp;&nbsp;</p>
<p>4.close()关闭所有连接。 &nbsp;&nbsp;&nbsp;</p>
<p>5.supportsAggressiveRelease()方法和hibernate.connection.release_mode配置参数有关，该参数用来指定使用哪一种连接释放模式。HIBERNATE参考手册是这样描的： &nbsp;&nbsp;&nbsp; Hibernate关于JDBC连接管理的旧(2.x)行为是，Session在第一次需要的时候获取一个连接，在session关闭之前一直会持有这个连接。Hibernate引入了连接释放的概念，来告诉session如何处理它的JDBC连接。注意，下面的讨论只适用于采用配置ConnectionProvider来提供连接的情况，用户自己提供的连接与这里的讨论无关。通过org.hibernate.hibernate.connection.release_mode的不同枚举值来使用不用的释放模式: &nbsp;&nbsp;&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; ON_CLOSE - 基本上就是上面提到的老式行为。Hibernate session在第一次需要进行JDBC操作的时候获取连接，然后持有它，直到session关闭。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; AFTER_TRANSACTION - 在org.hibernate.Transaction结束后释放连接。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; AFTER_STATEMENT (也被称做积极释放) - 在每一条语句被执行后就释放连接。但假若语句留下了与session相关的资源，那就不会被释放。目前唯一的这种情形就是使用org.hibernate.ScrollableResults &nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; auto(默认) - 这一选择把释放模式委派给org.hibernate.transaction.TransactionFactory.getDefaultReleaseMode()方法。对JTATransactionFactory来说，它会返回hibernate.connection.release_mode.AFTER_STATEMENT;对JDBCTransactionFactory来说，则是hibernate.connection.release_mode.AFTER_TRANSACTION。很少需要修改这一默认行为，因为假若设置不当，就会带来bug，或者给用户代码带来误导。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; on_close - 使用 hibernate.connection.release_mode.ON_CLOSE. 这种方式是为了向下兼容的,但是已经完全不被鼓励使用了。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; after_transaction - 使用hibernate.connection.release_mode.AFTER_TRANSACTION。这一设置不应该在JTA环境下使用。也要注意，使用hibernate.connection.release_mode.AFTER_TRANSACTION的时候，假若session 处于auto-commit状态，连接会像AFTER_STATEMENT那样被释放。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; after_statement - 使用hibernate.connection.release_mode.AFTER_STATEMENT。除此之外，会查询配置的ConnectionProvider，是否它支持这一设置（(supportsAggressiveRelease())）。假若不支持，释放模式会被设置为hibernate.connection.release_mode.AFTER_TRANSACTION。只有在你每次调用ConnectionProvider.getConnection()获取底层JDBC连接的时候，都可以确信获得同一个连接的时候，这一设置才是安全的；或者在auto-commit环境中，你可以不管是否每次都获得同一个连接的时候，这才是安全的。也就是说supportsAggressiveRelease()返回false的时候，释放模式会被设置为hibernate.connection.release_mode.AFTER_TRANSACTION。如果返回true,只表示它支持使用hibernate.connection.release_mode.AFTER_STATEMENT这一个设置，并不表示一定使用这个设置，请注意。</p></div></div><img src ="http://www.blogjava.net/freeman1984/aggbug/355110.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-07-27 11:15 <a href="http://www.blogjava.net/freeman1984/archive/2011/07/27/355110.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate自定义主键策略</title><link>http://www.blogjava.net/freeman1984/archive/2011/05/16/350334.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 16 May 2011 09:09:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2011/05/16/350334.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/350334.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2011/05/16/350334.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/350334.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/350334.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: hibernate自定义主键策略&nbsp;&nbsp;<a href='http://www.blogjava.net/freeman1984/archive/2011/05/16/350334.html'>阅读全文</a><img src ="http://www.blogjava.net/freeman1984/aggbug/350334.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2011-05-16 17:09 <a href="http://www.blogjava.net/freeman1984/archive/2011/05/16/350334.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>加速你的Hibernate引擎（下）</title><link>http://www.blogjava.net/freeman1984/archive/2010/11/15/338065.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 15 Nov 2010 02:19:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/11/15/338065.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/338065.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/11/15/338065.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/338065.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/338065.html</trackback:ping><description><![CDATA[<h3>4.6 HQL调优</h3>
<h4>4.6.1 索引调优</h4>
<p>HQL看起来和SQL很相似。从HQL的WHERE子句中通常可以猜到相应的SQL WHERE子句。WHERE子句中的字段决定了数据库将选择的索引。</p>
<p>大多数Hibernate开发者所常犯的一个错误是无论何时，当需要新WHERE子句的时候都会创建一个新的索引。因为索引会带来额外的数据更新开销，所以应该争取创建少量索引来覆盖尽可能多的查询。<br />
<strong>4.1节</strong>让你使用一个集合来处理所有可能的数据搜索条件。如果这不太实际，那么你可以使用后端剖析工具来创建一个针对应用程序涉及的所有SQL的集合。基于那些搜索条件的分类，你最终会得到一个小的索引集。与此同时，还可以尝试向WHERE子句中添加额外的谓语来匹配其他WHERE子句。</p>
<blockquote>
<p><strong>范例7</strong></p>
<p>有两个UI搜索器和一个后端守护进程搜索器来搜索名为iso_deals的表。第一个UI搜索器在unexpectedFlag、dealStatus、tradeDate和isold属性上有谓语。</p>
<p>第二个UI搜索器基于用户键入的过滤器，其中包括的内容除tradeDate和isold以外还有其他属性。开始时所有这些过滤器属性都是可选的。<br />
后端搜索器基于isold、participantCode和transactionType属性。<br />
经过进一步业务分析，发现第二个UI搜索器实际是基于一些隐式的unexpectedFlag和dealStatus值来选择数据的。我们还让tradeDate成为过滤器的必要属性（为了使用数据库索引，每个搜索过滤器都应该有必要属性）。</p>
<p>鉴于这一点，我们依次使用unexpectedFlag、dealStatus、tradeDate和isold构造了一个复合索引。两个UI搜索器都能共用它。（顺序很重要，如果你的谓语以不同的顺序指定这些属性或在它们前罗列了其他属性，数据库就不会选择该复合索引。）</p>
<p>后端搜索器和UI搜索器区别太大，因此我们不得不为它构造另一个复合索引，依次使用isold、participantCode和transactionType。</p>
</blockquote>
<h4>4.6.2绑定参数 vs.字符串拼接</h4>
<p>既可以使用绑定参数构造HQL的WHERE子句，也可以使用字符串拼接的方法，该决定对性能会有一定影响。使用绑定参数的原因是让数据库一次解析SQL，对后续的重复请求复用生成好的执行计划，这样做节省了CPU时间和内存。然而，为达到最优的数据访问效率，不同的绑定值可能需要不同的SQL执行计划。</p>
<p>例如，一小段数据范围可能只返回数据总量的5%，而一大段数据范围可能返回数据总量的90%。前者使用索引更好，而后者则最好使用全表扫描。</p>
<p>建议OLTP使用绑定参数，数据仓库使用字符串拼接，因为OLTP通常在一个事务中重复插入和更新数据，只取少量数据；数据仓库通常只有少量SQL查询，有一个确定的执行计划比节省CPU时间和内存更为重要。</p>
<p>要是你知道你的OLTP搜索对不同绑定值应该使用相同执行计划又该怎么办呢？</p>
<p>Oracle 9i及以后版本在第一次调用绑定参数并生成执行计划时能探出参数值。后续调用不会再探测，而是重用之前的执行计划。</p>
<h4>4.6.3聚合及排序</h4>
<p>你可以在数据库中进行聚合和&#8220;order by&#8221;，也可以在应用程序的服务层中事先加载所有数据然后做聚合和&#8220;order by&#8221;操作。推荐使用前者，因为数据库在这方面通常会比你的应用程序做得好。此外，这样做还能节省网络带宽，这也是一种拥有跨数据库移植性的做法。</p>
<p>当你的应用程序对数据聚合和排序有HQL不支持的特定业务规则时除外。</p>
<h4>4.6.4覆盖抓取策略</h4>
<p>详见<strong>4.7.1节</strong>。</p>
<h4>4.6.5本地查询</h4>
<p>本地查询调优其实并不直接与HQL有关。但HQL的确可以让你直接向底层数据库传递本地查询。我们并不建议这么做，因为本地查询在数据库间不可移植。</p>
<h3>4.7抓取策略调优</h3>
<p>抓取策略决定了在应用程序需要访问关联对象时，Hibernate以何种方式以及何时获取关联对象。HRD中的<a href="http://docs.jboss.org/hibernate/stable/core/reference/en/html/performance.html">第20章&#8220;改善性能&#8221;</a>对该主题作了很好的阐述，我们在此将关注它的使用方法。</p>
<h4>4.7.1覆盖抓取策略</h4>
<p>不同的用户可能会有不同的数据抓取要求。Hibernate允许在两个地方定义数据抓取策略，一处是在映射元数据中，另一处是在HQL或Criteria中覆盖它。</p>
<p>常见的做法是基于主要的抓取用例在映射元数据中定义默认抓取策略，针对少数用例在HQL和Criteria中覆盖抓取策略。</p>
<p>假设pojoA和pojoB是父子关系实例。如果根据业务规则，只是偶尔需要从实体两端加载数据，那你可以声明一个延迟加载集合或代理抓取（proxy fetching）。当你需要从实体两端获取数据时，可以用立即抓取（eager fetching）覆盖默认策略，例如使用HQL或Criteria配置连接抓取（join fetching）。</p>
<p>另一方面，如果业务规则在大多数时候需要从实体两端加载数据，那么你可以声明立即抓取并在Criteria中设置延迟加载集合或代理抓取来覆盖它（HQL目前还不支持这样的覆盖）。</p>
<h4>4.7.2 N+1模式或是反模式？</h4>
<p>select抓取会导致N+1问题。如果你知道自己总是需要从关联中加载数据，那么就该始终使用连接抓取。在下面两个场景中，你可能会把N+1视为一种模式而非反模式。</p>
<p>第一种场景，你不知道用户是否会访问关联对象。如果他/她没有访问，那么你赢了；否则你仍然需要额外的N次select SQL语句。这是一种令人左右为难的局面。</p>
<p>第二种场景，pojoA和很多其他POJO有one-to-many关联，例如pojoB和pojoC。使用立即的内连接或外连接抓取会在结果集中将pojoA重复很多次。当pojoA中有很多非空属性时，你不得不将大量数据加载到持久层中。这种加载需要很多时间，既有网络带宽的原因，如果Hibernate的会话是有状态的，其中也会有会话缓存的原因（内存消耗和GC暂停）。</p>
<p>如果你有一个很长的one-to-many关联链，例如从pojoA到pojoB到pojoC以此类推，情况也是类似的。</p>
<p>你也许会去使用HQL中的DISTINCT关键字或Cirteria中的distinct功能或是Java的Set接口来消除重复数据。但所有这些都是在Hibernate（在持久层）中实现的，而非数据库中。</p>
<p>如果基于你的网络和内存配置的测试表明N+1性能更好，那么你可以使用批量抓取、subselect抓取或二级缓存来做进一步调优。</p>
<blockquote>
<p><strong>范例8</strong></p>
<p>以下是一个使用批量抓取的HBM文件片段：</p>
<pre>&lt;<font color="#0080ff">class</font> <font color="#800000">name</font>=<em>"<font color="#0080ff">pojoA</font>" </em><font color="#800000">table</font>=<em>"<font color="#0080ff">pojoA</font>"</em>&gt;
&#8230;
&lt;<font color="#0080ff">set</font> <font color="#800000">name</font>=<em>"<font color="#0080ff">pojoBs</font>"</em> <font color="#800000">fetch</font>=<em>"<font color="#0080ff">select</font>"</em> <font color="#800000">batch-size</font>=<em>"<font color="#0080ff">10</font>"</em>&gt;
&lt;<font color="#0080ff">key</font> <font color="#800000">column</font>=<em>"<font color="#0080ff">pojoa_id</font>"</em>/&gt;
&#8230;
&lt;/<font color="#0080ff">set</font>&gt;
&lt;/<font color="#0080ff">class</font>&gt;
</pre>
<p>以下是多端pojoB生成的SQL：</p>
<pre><strong><font color="#800000">select</font></strong> &#8230; <strong><font color="#800000">from</font></strong> pojoB <strong><font color="#800000">where</font></strong> pojoa_id <strong><font color="#800000">in</font></strong>(?,?,?,?,?, ?,?,?,?,?);</pre>
<p>问号数量与batch-size值相等。因此N次额外的关于pojoB的select SQL语句被减少到了N/10次。</p>
<p>如果将<small><strong><font color="#800000">fetch</font>=<em>"<font color="#0080ff">select</font>"</em></strong></small>替换成<small><strong><font color="#800000">fetch</font>=<em>"<font color="#0080ff">subselect</font>"</em></strong></small>，pojoB生成的SQL语句就是这样的：</p>
<pre><strong><font color="#800000">select</font></strong> &#8230; <strong><font color="#800000">from</font></strong> pojoB <strong><font color="#800000">where</font></strong> pojoa_id <strong><font color="#800000">in</font></strong>(<strong><font color="#800000">select</font></strong> id <strong><font color="#800000">from</font></strong> pojoA <strong><font color="#800000">where</font></strong> &#8230;); </pre>
<p>尽管N次额外的select减少到1次，但这只在重复运行pojoA的查询开销很低时才有好处。</p>
<p>如果pojoA中的pojoB集合很稳定，或pojoB有pojoA的many-to-one关联，而且pojoA是只读引用数据，那么你可以使用二级缓存来缓存pojoA以消除N+1问题（<strong>4.8.1节</strong>中有一个例子）。</p>
</blockquote>
<h4>4.7.3延迟属性抓取</h4>
<p>除非有一张拥有很多你不需要的字段的遗留表，否则不应该使用这种抓取策略，因为它的延迟属性分组会带来额外的SQL。</p>
<p>在业务分析和设计过程中，你应该将不同数据获取或修改分组放到不同的领域对象实体中，而不是使用这种抓取策略。</p>
<p>如果不能重新设计遗留表，可以使用HQL或Criteria提供的投影功能来获取数据。</p>
<h4>4.8 二级缓存调优</h4>
<p>HRD<a href="http://docs.jboss.org/hibernate/stable/core/reference/en/html/performance.html#performance-cache">第20.2节 &#8220;二级缓存&#8221;</a>中的描述对大多数开发者来说过于简单，无法做出选择。3.3版及以后版本不再推荐使用基于&#8220;CacheProvider&#8221;的缓存，而用基于&#8220;RegionFactory&#8221;的缓存，这也让人更糊涂了。但是就算是最新的3.5参考文档也没有提及如何使用新缓存方法。</p>
<p>出于下述考虑，我们将继续关注于老方法：</p>
<ul>
    <li>所有流行的Hibernate二级缓存提供商中只有<a href="http://www.jboss.org/jbosscache">JBoss Cache 2</a>、<a href="http://www.jboss.org/infinispan">Infinispan 4</a>和<a href="http://ehcache.org/">Ehcache 2</a>支持新方法。<a href="http://www.opensymphony.com/oscache/">OSCache</a>、<a href="http://swarmcache.sourceforge.net/">SwarmCache</a>、<a href="http://www.oracle.com/technetwork/middleware/coherence/overview/index.html">Coherence</a>和<a href="http://www.gigaspaces.com/datagrid">Gigaspaces XAP-Data Grid</a>只支持老方法。
    <li>两种方法共用相同的&lt;cache&gt;配置。例如，它们仍旧使用相同的usage属性值&#8220;transactional|read-write|nonstrict-read-write|read-only&#8221;。
    <li>多个cache-region适配器仍然内置老方法的支持，理解它能帮助你快速理解新方法。 </li>
</ul>
<h4>4.8.1 基于CacheProvider的缓存机制</h4>
<p>理解该机制是做出合理选择的关键。关键的类/接口是CacheConcurrencyStrategy和它针对4中不同缓存使用的实现类，还有EntityUpdate/Delete/InsertAction。</p>
<p>针对并发缓存访问，有三种实现模式：</p>
<ul>
    <li><strong>针对&#8220;read-only&#8221;的只读模式。</strong>
    <p>无论是锁还是事务都没影响，因为缓存自数据从数据库加载后就不会改变。</p>
    <li><strong>针对&#8220;read-write&#8221;和&#8220;nonstrict-read-write&#8221;的非事务感知（non-transaction-aware）读写模式。</strong>
    <p>对缓存的更新发生在数据库事务完成后。缓存需要支持锁。</p>
    <li><strong>针对&#8220;transactional&#8221;的事务感知读写。</strong>
    <p>对缓存和数据库的更新被包装在同一个JTA事务中，这样缓存与数据库总是保持同步的。数据库和缓存都必须支持JTA。尽管缓存事务内部依赖于缓存锁，但Hibernate不会显式调用任何的缓存锁函数。</p>
    </li>
</ul>
<p>以数据库更新为例。EntityUpdateAction对于事务感知读写、&#8220;read-write&#8221;的非事务感知读写，还有&#8220;nonstrict-read-write&#8221;的非事务感知读写相应有如下调用序列：</p>
<ul>
    <li><strong>在一个JTA事务中更新数据库；在同一个事务中更新缓存。</strong>
    <li><strong>软锁缓存；在一个事务中更新数据库；在上一个事务成功完成后更新缓存；否则释放软锁。</strong>
    <p>软锁只是一种特定的缓存值失效表述方式，在它获得新数据库值前阻止其他事务读写缓存。那些事务会转而直接读取数据库。</p>
    <p>缓存必须支持锁；事务支持则不是必须的。如果缓存是一个集群，&#8220;更新缓存&#8221;的调用会将新值推送给所有副本，这通常被称为&#8220;推（push）&#8221;更新策略。</p>
    <li><strong>在一个事务中更新数据库；在上一个事务完成前就清除缓存；为了安全起见，无论事务成功与否，在事务完成后再次清除缓存。</strong>
    <p>既不需要支持缓存锁，也不需要支持事务。如果是缓存集群，&#8220;清除缓存&#8221;调用会让所有副本都失效，这通常被称为&#8220;拉（pull）&#8221;更新策略。</p>
    </li>
</ul>
<p>对于实体的删除或插入动作，或者集合变更，调用序列都是相似的。</p>
<p>实际上，最后两个异步调用序列仍能保证数据库和缓存的一致性（基本就是&#8220;read committed&#8221;的隔离了级别），这要归功于第二个序列中的软锁和&#8220;更新数据库&#8221;后的&#8220;更新缓存&#8221;，还有最后一个调用序列中的悲观&#8220;清除缓存&#8221;。</p>
<p>基于上述分析，我们的建议是：&nbsp;</p>
<ul>
    <li>如果数据是只读的，例如引用数据，那么总是使用&#8220;read-only&#8221;策略，因为它是最简单、最高效的策略，也是集群安全的策略。
    <li>除非你真的想将缓存更新和数据库更新放在一个JTA事务里，否则不要使用&#8220;transactional&#8221;策略，因为JTA需要漫长的两阶段提交处理，这导致它基本是性能最差的策略。
    <p>依笔者看来，二级缓存并非一级数据源，因此使用JTA也未必合理。实际上最后两个调用序列在大多数场景下是个不错的替代方案，这要归功于它们的数据一致性保障。</p>
    <li>如果你的数据读很多或者很少有并发缓存访问和更新，那么可以使用&#8220;nonstrict-read-write&#8221;策略。感谢它的轻量级&#8220;拉&#8221;更新策略，它通常是性能第二好的策略。
    <li>如果你的数据是又读又写的，那么使用&#8220;read-write&#8221;策略。这通常是性能倒数第二的策略，因为它要求有缓存锁，缓存集群中使用重量级的&#8220;推&#8221;更新策略。 </li>
</ul>
<blockquote>
<p><strong>范例9</strong></p>
<p>以下是一个ISO收费类型的HBM文件片段：</p>
<pre>&lt;<font color="#0080ff">class</font> <font color="#800000">name</font>=<em>"<font color="#0000ff">IsoChargeType</font>"&gt;</em>
&nbsp;&nbsp;&nbsp;&lt;<font color="#0080ff">property</font> <font color="#800000">name</font>=<em>"<font color="#0000ff">isoId</font>"</em> <font color="#800000">column</font>=<em>"<font color="#0000ff">ISO_ID</font>"</em> <font color="#800000">not-null</font>=<em>"<font color="#0000ff">true</font>"</em>/&gt;
&nbsp;&nbsp;&nbsp;&lt;<font color="#0080ff">many-to-one</font> <font color="#800000">name</font>=<em>"<font color="#0000ff">estimateMethod</font>"</em> <font color="#800000">fetch</font>=<em>"<font color="#0000ff">join</font>"</em> <font color="#800000">lazy</font>=<em>"<font color="#0000ff">false</font>"</em>/&gt;
&nbsp;&nbsp;&nbsp;&lt;<font color="#0080ff">many-to-one</font>  <font color="#800000">name</font>=<em>"<font color="#0000ff">allocationMethod</font>"</em> <font color="#800000">fetch</font>=<em>"<font color="#0000ff">join</font>"</em> <font color="#800000">lazy</font>=<em>"<font color="#0000ff">false</font>"</em>/&gt;
&nbsp;&nbsp;&nbsp;&lt;<font color="#0080ff">many-to-one</font> <font color="#800000">name</font>=<em>"<font color="#0000ff">chargeTypeCategory</font>"</em> <font color="#800000">fetch</font>=<em>"<font color="#0000ff">join</font>"</em> <font color="#800000">lazy</font>=<em>"<font color="#0000ff">false</font>"</em>/&gt;
&lt;/<font color="#0080ff">class</font>&gt; </pre>
<p>一些用户只需要ISO收费类型本身；一些用户既需要ISO收费类型，还需要它的三个关联对象。简单起见，开发者会立即加载所有三个关联对象。如果项目中没人负责Hibernate调优，这是很常见的。</p>
<p><strong>4.7.1节</strong>中讲过了最好的方法。因为所有的关联对象都是只读引用数据，另一种方法是使用延迟抓取，打开这些对象的二级缓存以避免N+1问题。实际上前一种方法也能从引用数据缓存中获益。</p>
<p>因为大多数项目都有很多被其他数据引用的只读引用数据，上述两种方法都能改善全局系统性能。</p>
</blockquote>
<h4>4.8.2 RegionFactory</h4>
<p>下表是新老两种方法中对应的主要类/接口：
<table cellspacing="0" cellpadding="0" border="1">
    <tbody>
        <tr>
            <td valign="top" width="295">
            <p><strong>新方法</strong></p>
            </td>
            <td valign="top" width="348">
            <p><strong>老方法</strong></p>
            </td>
        </tr>
        <tr>
            <td valign="top" width="295">
            <p>RegionFactory</p>
            </td>
            <td valign="top" width="348">
            <p>CacheProvider</p>
            </td>
        </tr>
        <tr>
            <td valign="top" width="295">
            <p>Region</p>
            </td>
            <td valign="top" width="348">
            <p>Cache</p>
            </td>
        </tr>
        <tr>
            <td valign="top" width="295">
            <p>EntityRegionAccessStrategy</p>
            </td>
            <td valign="top" width="348">
            <p>CacheConcurrencyStrategy</p>
            </td>
        </tr>
        <tr>
            <td valign="top" width="295">
            <p>CollectionRegionAccessStrategy</p>
            </td>
            <td valign="top" width="348">
            <p>CacheConcurrencyStrategy</p>
            </td>
        </tr>
    </tbody>
</table>
</p>
<p>第一个改进是RegionFactory构建了特定的Region，例如EntityRegion和TransactionRegion，而不是使用一个通用的访问Region。第二个改进是对于特定缓存的&#8220;usage&#8221;属性值，Region要求构建自己的访问策略，而不是所有Region都一直使用CacheConcurrencyStrategy的4种实现。</p>
<p>要使用新方法，应该设置factory_class而非provider_class配置属性。以Ehcache 2.0为例：</p>
<pre>&lt;property name="hibernate.cache.region.factory_class"&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; net.sf.ehcache.hibernate.EhCacheRegionFactory&nbsp;
&lt;/property&gt;</pre>
<p>其他相关的Hibernate缓存配置都和老方法一样。</p>
<p>新方法也能向后兼容遗留方法。如果还是只配了CacheProvider，新方法中将使用下列自说明（self-explanatory）适配器和桥隐式地调用老的接口/类：</p>
<p>RegionFactoryCacheProviderBridge、EntityRegionAdapter、CollectionRegionAdapter、QueryResultsRegionAdapter、EntityAccessStrategyAdapter和CollectionAccessStrategyAdapter</p>
<h4>4.8.3 查询缓存</h4>
<p>二级缓存也能缓存查询结果。如果查询开销很大而且要重复运行，这也会很有帮助。</p>
<h3>4.9批量处理调优</h3>
<p>大多数Hibernate的功能都很适合那些每个事务都通常只处理少量数据的OLTP系统。但是，如果你有一个数据仓库或者事务需要处理大量数据，那么就另当别论了。</p>
<h5>4.9.1使用有状态会话的非DML风格批处理</h5>
<p>如果你已经在使用常规会话了，那这是最自然的方法。你需要做三件事：</p>
<ul>
    <li>配置下列3个属性以开启批处理特性：
    <pre>&nbsp;&nbsp;hibernate.jdbc.batch_size 30
    &nbsp;&nbsp;hibernate.jdbc.batch_versioned_data true
    &nbsp;&nbsp;hibernate.cache.use_second_level_cache false</pre>
    <p>batch_size设置为正值会开启JDBC2的批量更新，Hibernate的建议值是5到30。基于我们的测试，极低值和极高值性能都很差。只要取值在合理范围内，区别就只有几秒而已。如果网络够快，这个结果是一定的。</p>
    <p>第二个配置设为true，这要求JDBC驱动在executeBatch()方法中返回正确的行数。对于Oracle用户而言，批量更新时不能将其设为true。请阅读Oracle的《JDBC Developer&#8217;s Guide and Reference》中的&#8220;<a href="http://download.oracle.com/docs/cd/B28359_01/java.111/b31224/oraperf.htm#g1068570">标准批处理的Oracle实现中的更新计数</a>&#8221;（<a href="http://download.oracle.com/docs/cd/B28359_01/java.111/b31224/oraperf.htm#g1068570">Update Counts in the Oracle Implementation of Standard Batching</a>）以获得更多详细信息。因为它对批量插入来说还是安全的，所以你可以为批量插入创建单独的专用数据源。最后一个配置项是可选的，因为你可以在会话中显式关闭二级缓存。</p>
    <li>像如下范例中那样定期刷新（flush）并清除一级会话缓存：
    <pre>&nbsp;Session session = sessionFactory.openSession();
    &nbsp;Transaction tx = session.beginTransaction();
    <p>&nbsp;for ( int i=0; i&lt;100000; i++ ) {<br />
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Customer customer = new Customer(.....);<br />
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//if your hibernate.cache.use_second_level_cache is true, call the following:<br />
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.setCacheMode(CacheMode.IGNORE);<br />
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.save(customer);<br />
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (i % 50 == 0) { //50, same as the JDBC batch size<br />
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//flush a batch of inserts and release memory:<br />
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.flush();<br />
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;session.clear();<br />
    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
    &nbsp;}<br />
    &nbsp;tx.commit();<br />
    &nbsp;session.close();</p>
    </pre>
    <p>批处理通常不需要数据缓存，否则你会将内存耗尽并大量增加GC开销。如果内存有限，那这种情况会很明显。</p>
    <li>总是将批量插入嵌套在事务中。 </li>
</ul>
<p>每次事务修改的对象数量越少就意味着会有更多数据库提交，正如<strong>4.5节</strong>所述每次提交都会带来磁盘相关的开销。</p>
<p>另一方面，每次事务修改的对象数量越多就意味着锁定变更时间越长，同时数据库需要更大的redo log。</p>
<h4>4.9.2使用无状态会话的非DML风格批处理</h4>
<p>无状态会话执行起来比上一种方法更好，因为它只是JDBC的简单包装，而且可以绕开很多常规会话要求的操作。例如，它不需要会话缓存，也不和任何二级缓存或查询缓存有交互。<br />
然而它的用法并不简单。尤其是它的操作并不会级联到所关联的实例上；你必须自己来处理它们。</p>
<h4>4.9.3 DML风格</h4>
<p>使用DML风格的插入、更新或删除，你直接在数据库中操作数据，这和前两种方法在Hibernate中操作数据的情况有所不同。</p>
<p>因为一个DML风格的更新或删除相当于前两种方法中的多个单独的更新或删除，所以如果更新或删除中的WHERE子句暗示了恰当的数据库索引，那么使用DML风格的操作能节省网络开销，执行得更好。</p>
<p>强烈建议结合使用DML风格操作和无状态会话。如果使用有状态会话，不要忘记在执行DML前清除缓存，否则Hibernate将会更新或清除相关缓存（见下面的范例10）。</p>
<h4>4.9.4批量加载</h4>
<p>如果你的HQL或Criteria会返回很多数据，那么要注意两件事：</p>
<ul>
    <li>用下列配置开启批量抓取特性：
    <pre>hibernate.jdbc.fetch_size 10</pre>
    <p>fetch_size设置为正值将开启JDBC批量抓取特性。相对快速网络，在慢速网络中这一点更为重要。Oracle建议的经验值是10。你应该基于自己的环境进行测试。</p>
    <li>在使用上述任一方法时都要关闭缓存，因为批量加载一般是一次性任务。受限于内存容量，向缓存中加载大量数据通常也意味着它们很快会被清除出去，这会增加GC开销。 </li>
</ul>
<blockquote>
<p><strong>范例10</strong></p>
<p>我们有一个后台任务，分段加载大量的IsoDeal数据用于后续处理。我们还会在分段数据交给下游系统处理前将其更新为处理中状态。最大的一段有50万行数据。以下是原始代码中截取出来的一段：</p>
<pre>Query query = session.createQuery("<font color="#0000ff">FROM IsoDeal d WHERE chunk-clause</font>");
query.setLockMode(<font color="#0000ff">"d"</font>, LockMode.<em><font color="#0000ff">UPGRADE</font></em>); //for Inprocess status update
List&lt;IsoDeal&gt; isoDeals = query.list();
for (IsoDeal isoDeal : isoDeals) { //update status to Inprocess
&nbsp;&nbsp;&nbsp;isoDeal.setStatus<font color="#0000ff">("Inprocess"</font>);
}
return isoDeals; </pre>
<p>包含上述代码的方法加上了Spring 2.5声明式事务的注解。加载并更新50万行数据大约花了10分钟。我们识别出了以下这些问题：</p>
<ul>
    <li>由于会话缓存和二级缓存的原因，系统会频繁地内存溢出。
    <li>就算没有内存溢出，当内存消耗很高时GC的开销也会很大。
    <li>我们还未设置fetch_size。
    <li>就算我们设置了batch_size，for循环也创建了太多update SQL语句。 </li>
</ul>
<p>不幸的是Spring 2.5不支持Hibernate无状态会话，所以我们只能关闭二级缓存；设置fetch_size；用DML风格的更新来代替for循环，以此改善性能。</p>
<p>但是，执行时间还是要6分钟。将Hibernate的日志级别调成trace后，我们发现是更新会话缓存造成了延时。通过在DML更新前清除会话缓存，我们将时间缩短到了4分钟，全部都是将数据加载到会话缓存中花费的时间。</p>
</blockquote>
<h3>4.10 SQL生成调优</h3>
<p>本节将向你展示如何减少SQL生成的数量。</p>
<h4>4.10.1 N+1抓取问题</h4>
<p>&#8220;select抓取&#8221;策略会导致N+1问题。如果&#8220;连接抓取&#8221;策略适合你的话，你应该始终使用该策略避免N+1问题。</p>
<p>但是，如果&#8220;连接抓取&#8221;策略执行效果不理想，就像<strong>4.7.2节</strong>中那样，你可以使用&#8220;subselect抓取&#8221;、&#8220;批量抓取&#8221;或&#8220;延迟集合抓取&#8221;来减少所需的额外SQL语句数。</p>
<h4>4.10.2 Insert+Update问题</h4>
<blockquote>
<p><strong>范例11</strong></p>
<p>我们的ElectricityDeal与DealCharge有单向one-to-many关联，如下列HBM文件片段所示：</p>
<pre>&lt;<font color="#0080ff">class</font> <font color="#800000">name</font>=<em>"<font color="#0000ff">ElectricityDeal</font>"</em>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#800000">select-before-update</font>=<em>"<font color="#0000ff">true</font>"</em> <font color="#800000">dynamic-update</font>=<em>"<font color="#0000ff">true</font>"</em>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#800000">dynamic-insert</font>=<em>"<font color="#0000ff">true</font>"</em>&gt;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0080ff">&lt;id</font> <font color="#800000">name</font>=<em>"<font color="#0000ff">key</font>"</em> <font color="#800000">column</font>=<em>"<font color="#0000ff">ID</font>"</em>&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0080ff">&lt;generator</font> <font color="#800000">class</font>=<em>"<font color="#0000ff">sequence</font>"</em>&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0080ff">&lt;param</font> <font color="#800000">name</font>=<em>"<font color="#0000ff">sequence</font>"</em>&gt;SEQ_ELECTRICITY_DEALS&lt;<font color="#0080ff">/param</font>&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0080ff">&lt;/generator&gt;</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0080ff">&lt;/id&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&#8230;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&lt;set</font> <font color="#800000">name</font>=<em>"<font color="#0000ff">dealCharges</font>" </em><font color="#800000">cascade</font>=<em>"<font color="#0000ff">all-delete-orphan</font>"&gt;</em>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0080ff">&lt;key </font><font color="#800000">column</font>=<em>"<font color="#0000ff">DEAL_KEY</font>"</em> <font color="#800000">not-null</font>=<em>"<font color="#0000ff">false</font>"</em> <font color="#800000">update</font>=<em>"<font color="#0000ff">true</font>"</em>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#800000">on-delete</font>=<em>"<font color="#0000ff">noaction</font>"</em>/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0080ff">&lt;one-to-many</font> <font color="#0000ff">class</font>=<em>"<font color="#0000ff">DealCharge</font>"</em>/&gt;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#0080ff">&lt;/set&gt;  &lt;/class&gt;</font> </pre>
</blockquote>
<p>在&#8220;key&#8221;元素中，&#8220;not-null&#8221;和&#8220;update&#8221;对应的默认值是false和true，上述代码为了明确这些取值，将它们写了出来。</p>
<p>如果你想创建一个ElectricityDeal和十个DealCharge，会生成如下SQL语句：</p>
<ul>
    <li>1句ElectricityDeal的插入语句；
    <li>10句DealCharge的插入语句，其中不包括外键&#8220;DEAL_KEY&#8221;；
    <li>10句DealCharge字段&#8220;DEAL_KEY&#8221;的更新语句。 </li>
</ul>
<p>为了消除那额外的10句更新语句，可以在那10句DealCharge插入语句中包含&#8220;DEAL_KEY&#8221;，你需要将&#8220;not-null&#8221;和&#8220;update&#8221;分别修改为true和false。</p>
<p>另一种做法是使用双向或many-to-one关联，让DealCharge来管理关联。</p>
<h4>4.10.3 更新前执行select</h4>
<p>在范例11中，我们为ElectricityDeal加上了select-before-update，这会对瞬时（transient）对象或分离（detached）对象产生额外的select语句，但却能避免不必要的数据库更新。</p>
<p>你应该做出一些权衡，如果对象没多少属性，不需要防止不必要的数据库更新，那么就不要使用该特性，因为你那些有限的数据既没有太多网络传输开销，也不会带来太多数据库更新开销。</p>
<p>如果对象的属性较多，例如是一张大的遗留表，那你应该开启该特性，和&#8220;dynamic-update&#8221;结合使用以避免太多数据库更新开销。</p>
<h4>4.10.4 级联删除</h4>
<p>在范例11中，如果你想删除1个ElectricityDeal和它的100个DealCharge，Hibernate会对DealCharge做100次删除。</p>
<p>如果将&#8220;on-delete&#8221;修改为&#8220;cascade&#8221;，Hibernate不会执行DealCharge的删除动作；而是让数据库根据ON CASCADE DELETE约束自动删除那100个DealCharge。不过，需要让DBA开启ON CASCADE DELETE约束，大多数DBA不愿意这么做，因为他们想避免父对象的意外删除级联到它的依赖对象上。此外，还要注意，该特性会绕过Hibernate对版本数据（versioned data）的常用乐观锁策略。</p>
<h4>4.10.5 增强的序列标识符生成器</h4>
<p>范例11中使用Oracle的序列作为标识符生成器。假设我们保存100个ElectricityDeal，Hibernate会将下面的SQL语句执行100次来获取下一个可用的标识符：</p>
<pre><strong><font color="#800000">select</font></strong> SEQ_ELECTRICITY_DEALS.NEXTVAL <strong><font color="#800000">from</font></strong> dual; </pre>
<p>如果网络不是很快，那这无疑会降低效率。3.2.3及后续版本中增加了一个增强的生成器&#8220;SequenceStyleGenerator&#8221;，它带了两个优化器：hilo和pooled。尽管HRD的<a href="http://docs.jboss.org/hibernate/stable/core/reference/en/html/mapping.html?bcsi_scan_3C4285B81B028A97=0&amp;bcsi_scan_filename=mapping.html">第5章&#8220;基础O/R映射&#8221;</a> 讲到了这两个优化器，不过内容有限。两个优化器都使用了HiLo算法，该算法生成的标识符等于Hi值加上Lo值，其中Hi值代表组号，Lo值顺序且重复地从1迭代到最大组大小，组号在Lo值&#8220;转回到&#8221;1时加1。</p>
<p>假设组大小是5（可以用max_lo或increment_size参数来表示），下面是个例子：</p>
<p><a href="http://www.infoq.com/resource/articles/hibernate_tuning/en/resources/tablelarge.jpg"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" alt="" src="http://www.infoq.com/resource/articles/hibernate_tuning-ii/zh/resources/table1.jpg" _href="img://table.jpg" _p="true" /></a></p>
<ul>
    <li>hilo优化器
    <p>组号取自数据库序列的下一个可用值，Hi值由Hibernate定义，是组号乘以increment_size参数值。</p>
    <li>pooled优化器
    <p>Hi值直接取自数据库序列的下一个可用值。数据库序列的增量应该设置为increment_size参数值。</p>
    </li>
</ul>
<p>直到内存组中的值耗尽后，两个优化器才会去访问数据库，上面的例子每5个标识值符访问一次数据库。使用hilo优化器时，你的序列不能再被其他应用程序使用，除非它们使用与Hibernate相同的逻辑。使用pooled优化器，在其他应用程序使用同一序列时则相当安全。</p>
<p>两个优化器都有一个问题，如果Hibernate崩溃，当前组内的一些标识符值就会丢失，然而大多数应用程序都不要求拥有连续的标识符值（如果你的数据库，比方说Oracle，缓存了序列值，当它崩溃时你也会丢失标识符值）。</p>
<p>如果在范例11中使用pooled优化器，新的id配置如下：</p>
<pre><font color="#0080ff">&lt;id</font> <font color="#800000">name</font>=<em>"key"</em> <font color="#800000">column</font>=<em>"<font color="#0000ff">ID"</font></em><font color="#0000ff">&gt;</font>
<font color="#0080ff">&lt;generator</font> <font color="#800000">class</font>=<font color="#0000ff"><em>"org.hibernate.id.enhance</em>.<em>SequenceStyleGenerator"</em>&gt;<br />
</font>        <font color="#0080ff">&lt;param</font> <font color="#800000">name</font>=<font color="#0000ff"><em>"sequence_name"</em>&gt;</font>SEQ_ELECTRICITY_DEALS<font color="#0080ff">&lt;/param&gt;</font>
<font color="#0080ff">&lt;param</font> <font color="#800000">name</font>=<font color="#0000ff"><em>"initial_value"</em>&gt;</font>0<font color="#0080ff">&lt;/param&gt;</font>
<font color="#0080ff">&lt;param</font> <font color="#800000">name</font>=<font color="#0000ff"><em>"increment_size"</em>&gt;</font>100<font color="#0080ff">&lt;/param&gt;</font>
<font color="#0080ff">&lt;param</font> <font color="#800000">name</font>=<font color="#0000ff"><em>"optimizer "</em>&gt;</font>pooled<font color="#0080ff">&lt;/param&gt;</font>
<font color="#0080ff">&lt;/generator&gt;</font>
<font color="#0080ff">&lt;/id&gt;</font> </pre>
<h2>5 总结</h2>
<p>本文涵盖了大多数你在Hibernate应用程序调优时会觉得很有用的调优技巧，其中的大多数时间都在讨论那些行之有效却缺乏文档的调优主题，例如继承映射、二级缓存和增强的序列标识符生成器。</p>
<p>它还提到了一些Hibernate调优所必需的数据库知识。一些范例中包含了你可能遇到的问题的实际解决方案。</p>
<p>除此之外，值得一提的是Hibernate也可以和In-Memory Data Grid（IMDG）一起使用，例如Oracle的Coherance或GigaSpaces IMDG，这能让你的应用程序达到毫秒级别</p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/338065.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-11-15 10:19 <a href="http://www.blogjava.net/freeman1984/archive/2010/11/15/338065.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>加速你的Hibernate引擎（上）</title><link>http://www.blogjava.net/freeman1984/archive/2010/11/15/338064.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 15 Nov 2010 02:18:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/11/15/338064.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/338064.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/11/15/338064.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/338064.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/338064.html</trackback:ping><description><![CDATA[<h2>1.引言</h2>
<p><a href="http://www.hibernate.org/">Hibernate</a>是最流行的对象关系映射（ORM）引擎之一，它提供了数据持久化和查询服务。</p>
<div class="vendor-content-box-float">
<h3>相关<span class="vendor">厂商</span>内容</h3>
<p class="entrypdf f_vcrembed" jsh='{"title":"甲骨文在JavaOne上阐述Java计划","id":1129}'><a href="http://www.infoq.com/cn/vendorcontent/show.action?vcr=1129" target="_blank">甲骨文在JavaOne上阐述Java计划 </a></p>
<p class="entrypdf f_vcrembed" jsh='{"title":"Adobe Flash Builder 4简体中文正式版高速下载","id":664}'><a href="http://www.infoq.com/cn/vendorcontent/show.action?vcr=664">Adobe Flash Builder 4简体中文正式版高速下载 </a></p>
<p class="entrypdf f_vcrembed" jsh='{"title":"创建您的第一个Flex和Facebook应用程序——第一部分：本地构建和测试（下）","id":1198}'><a href="http://www.infoq.com/cn/vendorcontent/show.action?vcr=1198">创建您的第一个Flex和Facebook应用程序——第一部分：本地构建和测试（下） </a></p>
<p class="entrypdf f_vcrembed" jsh='{"title":"QClub北京报名：地图API和LBS技术的应用优化(11月20日 周六)","id":1200}'><a href="http://www.infoq.com/cn/vendorcontent/show.action?vcr=1200">QClub北京报名：地图API和LBS技术的应用优化(11月20日 周六) </a></p>
<p class="entrypdf f_vcrembed" jsh='{"title":"实现适用于电视上的Flash Platform的视频和内容","id":1202}'><a href="http://www.infoq.com/cn/vendorcontent/show.action?vcr=1202">实现适用于电视上的Flash Platform的视频和内容 </a></p>
</div>
<p>在你的项目中引入Hibernate并让它跑起来是很容易的。但是，要让它跑得好却是需要很多时间和经验的。</p>
<p>通过我们的使用Hibernate 3.3.1和Oracle 9i的能源项目中的一些例子，本文涵盖了很多Hibernate调优技术。其中还提供了一些掌握Hibernate调优技术所必需的数据库知识。</p>
<p>我们假设读者对Hibernate有一个基本的了解。如果一个调优方法在Hibernate 参考文档（下文简称HRD）或其他调优文章中有详细描述，我们仅提供一个对该文档的引用并从不同角度对其做简单说明。我们关注于那些行之有效，但又缺乏文档的调优方法。</p>
<h2>2.Hibernate性能调优</h2>
<p>调优是一个迭代的、持续进行的过程，涉及软件开发生命周期（SDLC）的所有阶段。在一个典型的使用Hibernate进行持久化的Java EE应用程序中，调优会涉及以下几个方面：</p>
<ul>
    <li>业务规则调优
    <li>设计调优
    <li>Hibernate调优
    <li>Java GC调优
    <li>应用程序容器调优
    <li>底层系统调优，包括数据库和OS。 </li>
</ul>
<p>没有一套精心设计的方案就去进行以上调优是非常耗时的，而且很可能收效甚微。好的调优方法的重要部分是为调优内容划分优先级。可以用Pareto定律（又称&#8220;80/20法则&#8221;）来解释这一点，即通常80%的应用程序性能改善源自头20%的性能问题<sup>[5]</sup>。</p>
<p>相比基于磁盘和网络的访问，基于内存和CPU的访问能提供更低的延迟和更高的吞吐量。这种基于IO的Hibernate调优与底层系统IO部分的调优应该优先于基于CPU和内存的底层系统GC、CPU和内存部分的调优。</p>
<blockquote>
<p><strong>范例1</strong></p>
<p>我们调优了一个选择电流的HQL查询，把它从30秒降到了1秒以内。如果我们在垃圾回收方面下功夫，可能收效甚微——也许只有几毫秒或者最多几秒，相比HQL的改进，GC方面的改善可以忽略不计。</p>
</blockquote>
<p>好的调优方法的另一个重要部分是决定何时优化<sup>[4]</sup>。</p>
<p>积极优化的提倡者主张开始时就进行调优，例如在业务规则和设计阶段，在整个SDLC都持续进行优化，因为他们认为后期改变业务规则和重新设计代价太大。</p>
<p>另一派人提倡在SDLC末期进行调优，因为他们抱怨前期调优经常会让设计和编码变得复杂。他们经常引用Donald Knuth的名言&#8220;<em>过早优化是万恶之源</em>&#8221;<sup> [6]</sup>。</p>
<p>为了平衡调优和编码需要一些权衡。根据笔者的经验，适当的前期调优能带来更明智的设计和细致的编码。很多项目就失败在应用程序调优上，因为上面提到的&#8220;过早优化&#8221;阶段在被引用时脱离了上下文，而且相应的调优不是被推迟得太晚就是投入资源过少。</p>
<p>但是，要做很多前期调优也不太可能，因为没有经过剖析，你并不能确定应用程序的瓶颈究竟在何处，应用程序一般都是这样演化的。</p>
<p>对我们的多线程企业级应用程序的剖析也表现出大多数应用程序平均只有20-50%的CPU使用率。剩余的CPU开销只是在等待数据库和网络相关的IO。</p>
<p>基于上述分析，我们得出这样一个结论，结合业务规则和设计的Hibernate调优在Pareto定律中20%的那个部分，相应的它们的优先级更高。</p>
<p>一种比较实际的做法是：</p>
<ol>
    <li>识别出主要瓶颈，可以预见其中多数是Hibernate、业务规则和设计方面的（其数量视你的调优目标而定；但三到五个是不错的开端）。
    <li>修改应用程序以便消除这些瓶颈。
    <li>测试应用程序，然后重复步骤1，直到达到你的调优目标为止。 </li>
</ol>
<p>你能在Jack Shirazi的《Java Performance Tuning》 <sup>[7]</sup>一书中找到更多关于性能调优阶段的常见建议。</p>
<p>下面的章节中，我们会按照调优的大致顺序（列在前面的通常影响最大）去解释一些特定的调优技术。</p>
<h2>3. 监控和剖析</h2>
<p>没有对Hibernate应用程序的有效监控和剖析，你无法得知性能瓶颈以及何处需要调优。</p>
<h3>3.1.1 监控SQL生成</h3>
<p>尽管使用Hibernate的主要目的是将你从直接使用SQL的痛苦中解救出来，为了对应用程序进行调优，你必须知道Hibernate生成了哪些SQL。JoeSplosky在他的《The Law of Leaky Abstractions》一文中详细描述了这个问题。</p>
<p>你可以在log4j中将<strong>org.hibernate.SQL</strong>包的日志级别设为DEBUG，这样便能看到生成的所有SQL。你还可以将其他包的日志级别设为DEBUG，甚至TRACE来定位一些性能问题。</p>
<h3>3.1.2 查看Hibernate统计</h3>
<p>如果开启<strong>hibernate.generate.statistics</strong>，Hibernate会导出实体、集合、会话、二级缓存、查询和会话工厂的统计信息，这对通过<strong>SessionFactory.getStatistics()</strong>进行的调优很有帮助。为了简单起见，Hibernate还可以使用MBean&#8220;<strong>org.hibernate.jmx.StatisticsService</strong>&#8221;通过JMX来导出统计信息。你可以<u>在这个网站找到配置范例</u><u> </u><u>。</u></p>
<h3>3.1.3 剖析</h3>
<p>一个好的剖析工具不仅有利于Hibernate调优，还能为应用程序的其他部分带来好处。然而，大多数商业工具（例如JProbe <sup>[10]</sup>）都很昂贵。幸运的是Sun/Oracle的JDK1.6自带了一个名为&#8220;Java VisualVM&#8221; <sup>[11]</sup>的调试接口。虽然比起那些商业竞争对手，它还相当基础，但它提供了很多调试和调优信息。</p>
<h2>4. 调优技术</h2>
<h3>4.1 业务规则与设计调优</h3>
<p>尽管业务规则和设计调优并不属于Hibernate调优的范畴，但此处的决定对后面Hibernate的调优有很大影响。因此我们特意指出一些与Hibernate调优有关的点。</p>
<p>在业务需求收集与调优过程中，你需要知道：</p>
<ul>
    <li>数据获取特性包括引用数据（reference data）、只读数据、读分组（read group）、读取大小、搜索条件以及数据分组和聚合。
    <li>数据修改特性包括数据变更、变更组、变更大小、无效修改补偿、数据库（所有变更都在一个数据库中或在多个数据库中）、变更频率和并发性，以及变更响应和吞吐量要求。
    <li>数据关系，例如关联（association）、泛化（generalization）、实现（realization）和依赖（dependency）。 </li>
</ul>
<p>基于业务需求，你会得到一个最优设计，其中决定了应用程序类型（是OLTP还是数据仓库，亦或者与其中某一种比较接近）和分层结构（将持久层和服务层分离还是合并），创建领域对象（通常是POJO），决定数据聚合的地方（在数据库中进行聚合能利用强大的数据库功能，节省网络带宽；但是除了像COUNT、SUM、AVG、MIN和MAX这样的标准聚合，其他的聚合通常不具有移植性。在应用服务器上进行聚合允许你应用更复杂的业务逻辑；但你需要先在应用程序中载入详细的数据）。</p>
<blockquote>
<p><strong>范例2</strong></p>
<p>分析员需要查看一个取自大数据表的电流ISO（Independent System Operator）聚合列表。最开始他们想要显示大多数字段，尽管数据库能在1分钟内做出响应，应用程序也要花30分钟将1百万行数据加载到前端UI。经过重新分析，分析员保留了14个字段。因为去掉了很多可选的高聚合度字段，从剩下的字段中进行聚合分组返回的数据要少很多，而且大多数情况下的数据加载时间也缩小到了可接受的范围内。</p>
<p><strong>范例3</strong></p>
<p>过24个&#8220;非标准&#8221;（shaped，表示每小时都可以有自己的电量和价格；如果所有24小时的电量和价格相同，我们称之为&#8220;标准&#8221;）小时会修改小时电流交易，其中包括2个属性：每小时电量和价格。起初我们使用Hibernate的<em>select-before-update</em>特性，就是更新24行数据需要24次选择。因为我们只需要2个属性，而且如果不修改电量或价格的话也没有业务规则禁止无效修改，我们就关闭了<em>select-before-update</em>特性，避免了24次选择。</p>
</blockquote>
<h3>4.2继承映射调优</h3>
<p>尽管继承映射是领域对象的一部分，出于它的重要性我们将它单独出来。HRD <sup>[1]</sup>中的<a href="http://docs.jboss.org/hibernate/stable/core/reference/en/html/inheritance.html">第9章&#8220;继承映射&#8221;</a>已经说得很清楚了，所以我们将关注SQL生成和针对每个策略的调优建议。</p>
<p>以下是HRD中范例的类图：</p>
<p><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" alt="" src="http://www.infoq.com/resource/articles/hibernate_tuning/zh/resources/image1.jpg" _href="img://image1.jpg" _p="true" /><a><br />
</a></p>
<h4>4.2.1 每个类层次一张表</h4>
<p>只需要一张表，一条多态查询生成的SQL大概是这样的：</p>
<pre>select id, payment_type, amount, currency, rtn, credit_card_type <strong>from</strong> payment</pre>
<p>针对具体子类（例如CashPayment）的查询生成的SQL是这样的：</p>
<pre>select id, amount, currency <strong>from</strong> payment <strong>where</strong> payment_type=&#8217;CASH&#8217; </pre>
<p>这样做的优点包括只有一张表、查询简单以及容易与其他表进行关联。第二个查询中不需要包含其他子类中的属性。所有这些特性让该策略的性能调优要比其他策略容易得多。这种方法通常比较适合数据仓库系统，因为所有数据都在一张表里，不需要做表连接。</p>
<p>主要的缺点整个类层次中的所有属性都挤在一张大表里，如果有很多子类特有的属性，数据库中就会有太多字段的取值为null，这为当前基于行的数据库（使用基于列的DBMS的数据仓库处理这个会更好些）的SQL调优增加了难度。除非进行分区，否则唯一的数据表会成为热点，OLTP系统通常在这方面都不太好。</p>
<h4>4.2.2每个子类一张表</h4>
<p>需要4张表，多态查询生成的SQL如下：</p>
<pre><font color="#800000">select</font> id, payment_type, amount, currency, rtn, credit_card type,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case when c.payment_id <font color="#800000"><strong>is</strong> <strong>not</strong> <strong><font color="#0080ff">null</font></strong> <strong>then</strong></font> 1
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when ck.payment_id <font color="#800000"><strong>is</strong> <strong>not</strong> <strong><font color="#0080ff">null</font></strong> <strong>then</strong></font> 2
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when cc.payment_id <font color="#800000"><strong>is</strong> <strong>not</strong> <strong><font color="#0080ff">null</font></strong> <strong>then</strong></font> 3
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when p.id <font color="#800000"><strong>is</strong> <strong>not</strong> <strong><font color="#0080ff">null</font></strong> <strong>then</strong></font> 0 <font color="#800000"><strong>end</strong> <strong>as</strong></font> clazz
<strong><font color="#800000">from</font></strong> payment p <font color="#800000"><strong>left</strong> <strong>join</strong></font> cash_payment c <strong><font color="#800000">on</font></strong> p.id=c.payment_id <font color="#800000"><strong>left join</strong></font>
&nbsp;&nbsp;&nbsp;cheque_payment ck <strong><font color="#800000">on</font></strong> p.id=ck.payment_id <font color="#800000"><strong>left</strong> </font><strong><font color="#800000">join</font> </strong>
&nbsp;&nbsp;&nbsp;credit_payment cc <strong><font color="#800000">on</font></strong> p.id=cc.payment_id; </pre>
<p>针对具体子类（例如CashPayment）的查询生成的SQL是这样的：</p>
<pre><font color="#800000">select</font> id, payment_type, amount, currency
<strong><font color="#800000">from</font></strong> payment p <font color="#800000"><strong>left</strong> <strong>join</strong></font> cash_payment c <strong><font color="#800000">on</font></strong> p.id=c.payment_id; </pre>
<p>优点包括数据表比较紧凑（没有不需要的可空字段），数据跨三个子类的表进行分区，容易使用超类的表与其他表进行关联。紧凑的数据表可以针对基于行的数据库做存储块优化，让SQL执行得更好。数据分区增加了数据修改的并发性（除了超类，没有热点），OLTP系统通常会更好些。</p>
<p>同样的，第二个查询不需要包含其他子类的属性。</p>
<p>缺点是在所有策略中它使用的表和表连接最多，SQL语句稍显复杂（看看Hibernate动态鉴别器的长CASE子句）。相比单张表，数据库要花更多时间调优数据表连接，数据仓库在使用该策略时通常不太理想。</p>
<p>因为不能跨超类和子类的字段来建立复合索引，如果需要按这些列进行查询，性能会受影响。任何子类数据的修改都涉及两张表：超类的表和子类的表。</p>
<h4>4.2.3每个具体类一张表</h4>
<p>涉及三张或更多的表，多态查询生成的SQL是这样的：</p>
<pre><font color="#800000">select</font> p.id, p.amount, p.currency, p.rtn, p. credit_card_type, p.clazz
<font color="#800000"><strong>from</strong> (<strong>select</strong></font> id, amount, currency, <strong><font color="#0080ff">null</font></strong> <strong><font color="#800000">as</font></strong> rtn,<strong><font color="#0080ff">null</font></strong> <strong><font color="#800000">as</font></strong> credit_card type,
1 <strong><font color="#800000">as</font></strong> clazz <strong><font color="#800000">from</font></strong> cash_payment <font color="#800000"><strong>union</strong> <strong>all</strong></font>
<strong><font color="#800000">      select</font></strong> id, amount, <strong><font color="#0080ff">null</font></strong> <strong><font color="#800000">as</font></strong> currency, rtn,<strong><font color="#0080ff">null</font></strong> <strong><font color="#800000">as</font></strong> credit_card type,
2 <strong><font color="#800000">as</font></strong> clazz <strong><font color="#800000">from</font></strong> cheque_payment <font color="#800000"><strong>union</strong> <strong>all</strong></font>
<strong><font color="#800000">      select</font></strong> id, amount, <strong><font color="#0080ff">null</font></strong> <strong><font color="#800000">as</font></strong> currency, <strong><font color="#0080ff">null</font></strong> <strong><font color="#800000">as</font></strong> rtn,credit_card type,
3 <strong><font color="#800000">as</font></strong> clazz <strong><font color="#800000">from</font></strong> credit_payment) p;  </pre>
<p>针对具体子类（例如CashPayment）的查询生成的SQL是这样的：</p>
<pre><font color="#800000">select</font> id, payment_type, amount, currency <strong><font color="#800000">from</font></strong> cash_payment; </pre>
<p>优点和上面的&#8220;每个子类一张表&#8221;策略相似。因为超类通常是抽象的，所以具体的三张表是必须的[开头处说的3张或更多的表是必须的]，任何子类的数据修改只涉及一张表，运行起来更快。</p>
<p>缺点是SQL（from子句和union all子查询）太复杂。但是大多数数据库对此类SQL的调优都很好。</p>
<p>如果一个类想和Payment超类关联，数据库无法使用引用完整性（referential integrity）来实现它；必须使用触发器来实现它。这对数据库性能有些影响。</p>
<h4>4.2.4使用隐式多态实现每个具体类一张表</h4>
<p>只需要三张表。对于Payment的多态查询生成三条独立的SQL语句，每个对应一个子类。Hibernate引擎通过Java反射找出Payment的所有三个子类。</p>
<p>具体子类的查询只生成该子类的SQL。这些SQL语句都很简单，这里就不再阐述了。</p>
<p>它的优点和上节类似：紧凑数据表、跨三个具体子类的数据分区以及对子类任意数据的修改都只涉及一张表。</p>
<p>缺点是用三条独立的SQL语句代替了一条联合SQL，这会带来更多网络IO。Java反射也需要时间。假设如果你有一大堆领域对象，你从最上层的Object类进行隐式选择查询，那该需要多长时间啊！</p>
<p>根据你的映射策略制定合理的选择查询并非易事；这需要你仔细调优业务需求，基于特定的数据场景制定合理的设计决策。</p>
<p>以下是一些建议：</p>
<ul>
    <li>设计细粒度的类层次和粗粒度的数据表。细粒度的数据表意味着更多数据表连接，相应的查询也会更复杂。
    <li>如非必要，不要使用多态查询。正如上文所示，对具体类的查询只选择需要的数据，没有不必要的表连接和联合。
    <li>&#8220;每个类层次一张表&#8221;对有高并发、简单查询并且没有共享列的OLTP系统来说是个不错的选择。如果你想用数据库的引用完整性来做关联，那它也是个合适的选择。
    <li>&#8220;每个具体类一张表&#8221;对有高并发、复杂查询并且没有共享列的OLTP系统来说是个不错的选择。当然你不得不牺牲超类与其他类之间的关联。
    <li>采用混合策略，例如&#8220;每个类层次一张表&#8221;中嵌入&#8220;每个子类一张表&#8221;，这样可以利用不同策略的优势。随着你项目的进化，如果你要反复重新映射，那你可能也会采用该策略。
    <li>&#8220;使用隐式多态实现每个具体类一张表&#8221;这种做法并不推荐，因为其配置过于繁缛、使用&#8220;any&#8221;元素的复杂关联语法和隐式查询的潜在危险性。 </li>
</ul>
<blockquote>
<p><strong>范例4</strong></p>
<p>下面是一个交易描述应用程序的部分领域类图：</p>
<p><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" alt="" src="http://www.infoq.com/resource/articles/hibernate_tuning/zh/resources/image2.jpg" _href="img://image2.jpg" _p="true" /></p>
<p>开始时，项目只有GasDeal和少数用户，它使用&#8220;每个类层次一张表&#8221;。</p>
<p>OilDeal和ElectricityDeal是后期产生更多业务需求后加入的。没有改变映射策略。但是ElectricityDeal有太多自己的属性，因此有很多电相关的可空字段加入了Deal表。因为用户量也在增长，数据修改变得越来越慢。</p>
<p>重新设计时我们使用了两张单独的表，分别针对气/油和电相关的属性。新的映射混合了&#8220;每个类层次一张表&#8221;和&#8220;每个子类一张表&#8221;。我们还重新设计了查询，以便允许针对具体交易子类进行选择，消除不必要的列和表连接。</p>
</blockquote>
<h3>4.3 领域对象调优</h3>
<p>基于<strong>4.1</strong><strong>节</strong>中对业务规则和设计的调优，你得到了一个用POJO来表示的领域对象的类图。我们建议：</p>
<h4>4.3.1 POJO调优</h4>
<ul>
    <li>从读写数据中将类似引用这样的只读数据和以读为主的数据分离出来。<br />
    只读数据的二级缓存是最有效的，其次是以读为主的数据的非严格读写。将只读POJO标识为不可更改的（immutable）也是一个调优点。如果一个服务层方法只处理只读数据，可以将它的事务标为只读，这是优化Hibernate和底层JDBC驱动的一个方法。
    <li>细粒度的POJO和粗粒度的数据表。<br />
    基于数据的修改并发量和频率等内容来分解大的POJO。尽管你可以定义一个粒度非常细的对象模型，但粒度过细的表会导致大量表连接，这对数据仓库来说是不能接受的。
    <li>优先使用非final的类。<br />
    Hibernate只会针对非final的类使用CGLIB代理来实现延时关联获取。如果被关联的类是final的，Hibernate会一次加载所有内容，这对性能会有影响。
    <li>使用业务键为分离（detached）实例实现equals()和hashCode()方法。<br />
    在多层系统中，经常可以在分离对象上使用乐观锁来提升系统并发性，达到更高的性能。
    <li>定义一个版本或时间戳属性。<br />
    乐观锁需要这个字段来实现长对话（应用程序事务）[译注：session译为会话，conversion译为对话，以示区别]。
    <li>优先使用组合POJO。<br />
    你的前端UI经常需要来自多个不同POJO的数据。你应该向UI传递一个组合POJO而不是独立的POJO以获得更好的网络性能。<br />
    有两种方式在服务层构建组合POJO。一种是在开始时加3.2载所有需要的独立POJO，随后抽取需要的属性放入组合POJO；另一种是使用HQL投影，直接从数据库中选择需要的属性。<br />
    如果其他地方也要查找这些独立POJO，可以把它们放进二级缓存以便共享，这时第一种方式更好；其他情况下第二种方式更好。 </li>
</ul>
<h4>4.3.2 POJO之间关联的调优</h4>
<ul>
    <li>如果可以用one-to-one、one-to-many或many-to-one的关联，就不要使用many-to-many。
    <li>many-to-many关联需要额外的映射表。<br />
    尽管你的Java代码只需要处理两端的POJO，但查询时，数据库需要额外地关联映射表，修改时需要额外的删除和插入。
    <li>单向关联优先于双向关联。<br />
    由于many-to-many的特性，在双向关联的一端加载对象会触发另一端的加载，这会进一步触发原始端加载更多的数据，等等。<br />
    one-to-many和many-to-one的双向关联也是类似的，<a>当你从多端（子实体）定位到一端（父实体）</a>。<br />
    这样的来回加载很耗时，而且可能也不是你所期望的。
    <li>不要为了关联而定义关联；只在你需要一起加载它们时才这么做，这应该由你的业务规则和设计来决定（见<strong>范例</strong><strong>5</strong>）。<br />
    另外，你要么不定义任何关联，要么在子POJO中定义一个值类型的属性来表示父POJO的ID（另一个方向也是类似的）。
    <li>集合调优<br />
    如果集合排序逻辑能由底层数据库实现，就使用&#8220;order-by&#8221;属性来代替&#8220;sort&#8221;，因为通常数据库在这方面做得比你好。<br />
    集合可以是值类型的（元素或组合元素），也可以是实体引用类型的（one-to-many或many-to-many关联）。对引用类型集合的调优主要是调优获取策略。对于值类型集合的调优，HRD <sup>[1]</sup>中的<u>20.5</u><u>节&#8220;理解集合性能&#8221;</u>已经做了很好的阐述。
    <li>获取策略调优。请见<strong>4.7</strong><strong>节的范例</strong><strong>5</strong>。 </li>
</ul>
<blockquote>
<p><strong>范例5</strong></p>
<p>我们有一个名为ElectricityDeals的核心POJO用于描述电的交易。从业务角度来看，它有很多many-to-one关联，例如和Portfolio、Strategy和Trader等的关联。因为引用数据十分稳定，它们被缓存在前端，能基于其ID属性快速定位到它们。</p>
<p>为了有好的加载性能，ElectricityDeal只映射元数据，即那些引用POJO的值类型ID属性，因为在需要时，可以在前端通过portfolioKey从缓存中快速查找Portfolio：</p>
<pre><font color="#0080ff">&lt;property</font> <font color="#800000">name</font>=<em>"<font color="#0000ff">portfolioKey</font>"</em> <font color="#800000">column</font>=<font color="#0000ff"><em>"PORTFOLIO_ID" </em><font color="#800000">type</font>=<em>"</em>integer<em>"</em>/&gt;</font> </pre>
<p>这种隐式关联避免了数据库表连接和额外的字段选择，降低了数据传输的大小。</p>
</blockquote>
<h3>4.4 连接池调优</h3>
<p>由于创建物理数据库连接非常耗时，你应该始终使用连接池，而且应该始终使用生产级连接池而非Hibernate内置的基本连接池算法。</p>
<p>通常会为Hibernate提供一个有连接池功能的数据源。Apache DBCP的BasicDataSource<sup>[13]</sup>是一个流行的开源生产级数据源。大多数数据库厂商也实现了自己的兼容JDBC 3.0的连接池。举例来说，你也可以使用Oracle ReaApplication Cluster <sup>[15]</sup>提供的JDBC连接池<sup>[14]</sup>以获得连接的负载均衡和失败转移。</p>
<p>不用多说，你在网上能找到很多关于连接池调优的技术，因此我们只讨论那些大多数连接池所共有的通用调优参数：</p>
<ul>
    <li>最小池大小：连接池中可保持的最小连接数。
    <li>最大池大小：连接池中可以分配的最大连接数。<br />
    如果应用程序有高并发，而最大池大小又太小，连接池就会经常等待。相反，如果最小池大小太大，又会分配不需要的连接。
    <li>最大空闲时间：连接池中的连接被物理关闭前能保持空闲的最大时间。
    <li>最大等待时间：连接池等待连接返回的最大时间。该参数可以预防失控事务（runaway transaction）。
    <li>验证查询：在将连接返回给调用方前用于验证连接的SQL查询。这是因为一些数据库被配置为会杀掉长时间空闲的连接，网络或数据库相关的异常也可能会杀死连接。为了减少此类开销，连接池在空闲时会运行该验证。 </li>
</ul>
<h3>4.5事务和并发的调优</h3>
<p>短数据库事务对任何高性能、高可扩展性的应用程序来说都是必不可少的。你使用表示对话请求的会话来处理单个工作单元，以此来处理事务。</p>
<p>考虑到工作单元的范围和事务边界的划分，有3中模式：</p>
<ul>
    <li><strong>每次操作一个会话。</strong>每次数据库调用需要一个新会话和事务。因为真实的业务事务通常包含多个此类操作和大量小事务，这一般会引起更多数据库活动（主要是数据库每次提交需要将变更刷新到磁盘上），影响应用程序性能。这是一种反模式，不该使用它。
    <li><strong>使用分离对象，每次请求一个会话。</strong>每次客户端请求有一个新会话和一个事务，使用Hibernate的&#8220;当前会话&#8221;特性将两者关联起来。<br />
    在一个多层系统中，用户通常会发起长对话（或应用程序事务）。大多数时间我们使用Hibernate的自动版本和分离对象来实现乐观并发控制和高性能。
    <li><strong>带扩展（或长）会话的每次对话一会话。</strong>在一个也许会跨多个事务的长对话中保持会话开启。尽管这能把你从重新关联中解脱出来，但会话可能会内存溢出，在高并发系统中可能会有旧数据。 </li>
</ul>
<p>你还应该注意以下几点。&nbsp;</p>
<ul>
    <li>如果不需要JTA就用本地事务，因为JTA需要更多资源，比本地事务更慢。就算你有多个数据源，除非有跨多个数据库的事务，否则也不需要JTA。在最后的一个场景下，可以考虑在每个数据源中使用本地事务，使用一种类似&#8220;Last Resource Commit Optimization&#8221;<sup>[16]</sup>的技术（见下面的<strong>范例</strong><strong>6</strong>）。
    <li>如果不涉及数据变更，将事务标记为只读的，就像<strong>4.3.1</strong><strong>节</strong>提到的那样。
    <li>总是设置默认事务超时。保证在没有响应返回给用户时，没有行为不当的事务会完全占有资源。这对本地事务也同样有效。
    <li>如果Hibernate不是独占数据库用户，乐观锁会失效，除非创建数据库触发器为其他应用程序对相同数据的变更增加版本字段值。 </li>
</ul>
<blockquote>
<p><strong>范例6</strong></p>
<p>我们的应用程序有多个在大多数情况下只和数据库&#8220;A&#8221;打交道的服务层方法；它们偶尔也会从数据库&#8220;B&#8221;中获取只读数据。因为数据库&#8220;B&#8221;只提供只读数据，我们对这些方法在这两个数据库上仍然使用本地事务。</p>
<p>服务层上有一个方法设计在两个数据库上执行数据变更。以下是伪代码：</p>
<pre><font color="#008000">//Make sure a local transaction on database A exists</font>
@Transactional (readOnly=<strong><font color="#800000">false</font></strong>, propagation=Propagation.<em><font color="#0000ff">REQUIRED</font></em>)
<font color="#800000"><strong>public</strong> <strong>void</strong></font> saveIsoBids() {
<font color="#008000">  //it participates in the above annotated local transaction</font>
insertBidsInDatabaseA();
<font color="#008000">  //it runs in its own local transaction on database B </font>
insertBidRequestsInDatabaseB(); <font color="#008000">//must be the last operation </font></pre>
<p>因为<strong>insertBidRequestsInDatabaseB()</strong>是saveIsoBids ()中的最后一个方法，所以只有下面的场景会造成数据不一致：</p>
<p>在saveIsoBids()执行返回时，数据库&#8220;A&#8221;的本地事务提交失败。</p>
<p>但是，就算saveIsoBids()使用JTA，在两阶段提交（2PC）的第二个提交阶段失败的时候，你还是会碰到数据不一致。因此如果你能处理好上述的数据不一致性，而且不想为了一个或少数几个方法引入JTA的复杂性，你应该使用本地事务。</p>
</blockquote>
<p>（未完待续）</p>
<p><strong>关于作者</strong></p>
<p><strong>Yongjun Jiao</strong>是SunGard Consulting Services的技术主管。过去10年中他一直是专业软件开发者，他的专长包括Java SE、Java EE、Oracle和应用程序调优。他最近的关注点是高性能计算，包括内存数据网格、并行计算和网格计算。</p>
<p><strong>Stewart Clark</strong>是SunGard Consulting Services的负责人。过去15年中他一直是专业软件开发者和项目经理，他的专长包括Java核心编程、Oracle和能源交易。<br />
转载自infoq</p>
 <img src ="http://www.blogjava.net/freeman1984/aggbug/338064.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-11-15 10:18 <a href="http://www.blogjava.net/freeman1984/archive/2010/11/15/338064.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于@Transactional和配置文件混用的问题</title><link>http://www.blogjava.net/freeman1984/archive/2010/08/18/329225.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Wed, 18 Aug 2010 07:56:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/08/18/329225.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/329225.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/08/18/329225.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/329225.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/329225.html</trackback:ping><description><![CDATA[使用顺序：<br />
1&nbsp;&nbsp; &lt;tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /&gt;<br />
<br />
之后才是xml配置：<br />
&nbsp;2&nbsp; &lt;tx:advice id="txAdviceService" transaction-manager="transactionManager"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tx:attributes&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;tx:method name="add*" read-only="false"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tx:method name="add*" read-only="false"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tx:method name="update*" read-only="false"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tx:method name="del*" read-only="false"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;tx:method name="apply*" read-only="false"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;tx:method name="*" read-only="true"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/tx:attributes&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/tx:advice&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;aop:config&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;aop:pointcut id="serviceMethods"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; expression="execution(* com.joe.service.*.*(..))"/&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;aop:advisor advice-ref="txAdviceService" pointcut-ref="serviceMethods"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/aop:config&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp; &lt;bean id="transactionManager"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; class="org.springframework.orm.hibernate3.HibernateTransactionManager"&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="sessionFactory" ref="sessionFactory"/&gt;<br />
&nbsp;&nbsp;&nbsp; &lt;/bean&gt;<br />
如果写反会出现如果使用的<br />
@Transactional的方法在&nbsp; &lt;tx:method name="*" read-only="true"/&gt;<br />
里面 就会发现没有可写事务 ：<br />
error:Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.<br />
<img src ="http://www.blogjava.net/freeman1984/aggbug/329225.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-08-18 15:56 <a href="http://www.blogjava.net/freeman1984/archive/2010/08/18/329225.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring事务的传播行为和隔离级别 </title><link>http://www.blogjava.net/freeman1984/archive/2010/04/28/319595.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Wed, 28 Apr 2010 06:30:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/04/28/319595.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/319595.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/04/28/319595.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/319595.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/319595.html</trackback:ping><description><![CDATA[<p style="line-height: 150%; margin: 5px">转载自：http://blog.chinaunix.net/u1/55983/showart_2091761.html<code><span style="color: #000000"><br />
7个传播行为，4个隔离级别， <br />
<br />
Spring事务的传播行为和隔离级别<span style="color: #0000cc">[</span><span style="color: #ff0000">transaction</span> behavior <span style="color: #ff0000">and</span> isolated <span style="color: #ff0000">level</span><span style="color: #0000cc">]</span>2007<span style="color: #0000cc">-</span>08<span style="color: #0000cc">-</span>01 16<span style="color: #0000cc">:</span>33事务的传播行为和隔离级别<span style="color: #0000cc">[</span><span style="color: #ff0000">transaction</span> behavior <span style="color: #ff0000">and</span> isolated <span style="color: #ff0000">level</span><span style="color: #0000cc">]</span><br />
<br />
Spring中事务的定义：<br />
一、Propagation ：<br />
　　key属性确定代理应该给哪个方法增加事务行为。这样的属性最重要的部份是传播行为。有以下选项可供使用：<br />
PROPAGATION_REQUIRED<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>支持当前事务，如果当前没有事务，就新建一个事务。这是最常见的选择。 <br />
PROPAGATION_SUPPORTS<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>支持当前事务，如果当前没有事务，就以非事务方式执行。 <br />
PROPAGATION_MANDATORY<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>支持当前事务，如果当前没有事务，就抛出异常。 <br />
PROPAGATION_REQUIRES_NEW<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>新建事务，如果当前存在事务，把当前事务挂起。 <br />
PROPAGATION_NOT_SUPPORTED<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>以非事务方式执行操作，如果当前存在事务，就把当前事务挂起。 <br />
PROPAGATION_NEVER<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>以非事务方式执行，如果当前存在事务，则抛出异常。 <br />
<br />
很多人看到事务的传播行为属性都不甚了解，我昨晚看了j2ee without ejb的时候，看到这里也不了解，甚至重新翻起数据库系统的教材书，但是也没有找到对这个的分析。今天搜索，找到一篇极好的分析文章，虽然这篇文章是重点分析PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRED_NESTED的<br />
<span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><br />
&nbsp;&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
解惑 <span style="color: #ff0000">spring</span> 嵌套事务 <br />
<span style="color: #ff9900">/** <br />
* @date 2006-11-24 <br />
* @note 转载自http://www.javaeye.com/topic/35907?page=1<br />
*/</span> <br />
<span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span>TransactionDefinition 接口定义<span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><br />
<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Support a current transaction, create a new one if none exists. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Analogous to EJB transaction attribute of the same name. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* <br />
This is typically the default setting of a transaction definition. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">int</span> PROPAGATION_REQUIRED <span style="color: #0000cc">=</span> 0<span style="color: #0000cc">;</span> <br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Support a current transaction, execute non-transactionally if none exists. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Analogous to EJB transaction attribute of the same name. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* <br />
<br />
Note: For transaction managers with transaction synchronization, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* PROPAGATION_SUPPORTS is slightly different from no transaction at all, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* as it defines a transaction scopp that synchronization will apply for. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* As a consequence, the same resources (JDBC Connection, Hibernate Session, etc) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* will be shared for the entire specified scope. Note that this depends on <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* the actual synchronization configuration of the transaction manager. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">int</span> PROPAGATION_SUPPORTS <span style="color: #0000cc">=</span> 1<span style="color: #0000cc">;</span> <br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Support a current transaction, throw an exception if none exists. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Analogous to EJB transaction attribute of the same name. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">int</span> PROPAGATION_MANDATORY <span style="color: #0000cc">=</span> 2<span style="color: #0000cc">;</span> <br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Create a new transaction, suspend the current transaction if one exists. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Analogous to EJB transaction attribute of the same name. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* <br />
<br />
Note: Actual transaction suspension will not work on out-of-the-box <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* on all transaction managers. This in particular applies to JtaTransactionManager, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* which requires the javax.transaction.TransactionManager to be <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* made available it to it (which is server-specific in standard J2EE). <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">int</span> PROPAGATION_REQUIRES_NEW <span style="color: #0000cc">=</span> 3<span style="color: #0000cc">;</span> <br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Execute non-transactionally, suspend the current transaction if one exists. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Analogous to EJB transaction attribute of the same name. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* <br />
<br />
Note: Actual transaction suspension will not work on out-of-the-box <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* on all transaction managers. This in particular applies to JtaTransactionManager, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* which requires the javax.transaction.TransactionManager to be <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* made available it to it (which is server-specific in standard J2EE). <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">int</span> PROPAGATION_NOT_SUPPORTED <span style="color: #0000cc">=</span> 4<span style="color: #0000cc">;</span> <br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Execute non-transactionally, throw an exception if a transaction exists. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Analogous to EJB transaction attribute of the same name. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">int</span> PROPAGATION_NEVER <span style="color: #0000cc">=</span> 5<span style="color: #0000cc">;</span> <br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Execute within a nested transaction if a current transaction exists, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* behave like PROPAGATION_REQUIRED else. There is no analogous feature in EJB. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* <br />
<br />
Note: Actual creation of a nested transaction will only work on specific <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* transaction managers. Out of the box, this only applies to the JDBC <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* DataSourceTransactionManager when working on a JDBC 3.0 driver. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Some JTA providers might support nested transactions as well. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* @see org.springframework.jdbc.datasource.DataSourceTransactionManager <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">int</span> PROPAGATION_NESTED <span style="color: #0000cc">=</span> 6<span style="color: #0000cc">;</span> <br />
<br />
<span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><br />
在这篇文章里，他用两个嵌套的例子辅助分析，我这里直接引用了。<br />
<span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span>sample<span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><br />
ServiceA <span style="color: #0000cc">{</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* 事务属性配置为 PROPAGATION_REQUIRED <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">void</span> methodA<span style="color: #0000cc">(</span><span style="color: #0000cc">)</span> <span style="color: #0000cc">{</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ServiceB<span style="color: #0000cc">.</span>methodB<span style="color: #0000cc">(</span><span style="color: #0000cc">)</span><span style="color: #0000cc">;</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000cc">}</span> <br />
&nbsp;&nbsp;<br />
<span style="color: #0000cc">}</span> <br />
&nbsp;&nbsp;<br />
ServiceB <span style="color: #0000cc">{</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* 事务属性配置为 PROPAGATION_REQUIRED <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">void</span> methodB<span style="color: #0000cc">(</span><span style="color: #0000cc">)</span> <span style="color: #0000cc">{</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000cc">}</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #0000cc">}</span> <br />
<span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><br />
1： PROPAGATION_REQUIRED <br />
加入当前正要执行的事务不在另外一个事务里，那么就起一个新的事务 <br />
比如说，ServiceB<span style="color: #0000cc">.</span>methodB的事务级别定义为PROPAGATION_REQUIRED<span style="color: #0000cc">,</span> 那么由于执行ServiceA<span style="color: #0000cc">.</span>methodA的时候， <br />
ServiceA<span style="color: #0000cc">.</span>methodA已经起了事务，这时调用ServiceB<span style="color: #0000cc">.</span>methodB，ServiceB<span style="color: #0000cc">.</span>methodB看到自己已经运行在ServiceA<span style="color: #0000cc">.</span>methodA <br />
的事务内部，就不再起新的事务。而假如ServiceA<span style="color: #0000cc">.</span>methodA运行的时候发现自己没有在事务中，他就会为自己分配一个事务。 <br />
这样，在ServiceA<span style="color: #0000cc">.</span>methodA或者在ServiceB<span style="color: #0000cc">.</span>methodB内的任何地方出现异常，事务都会被回滚。即使ServiceB<span style="color: #0000cc">.</span>methodB的事务已经被 <br />
提交，但是ServiceA<span style="color: #0000cc">.</span>methodA在接下来fail要回滚，ServiceB<span style="color: #0000cc">.</span>methodB也要回滚 <br />
<br />
2： PROPAGATION_SUPPORTS <br />
如果当前在事务中，即以事务的形式运行，如果当前不再一个事务中，那么就以非事务的形式运行 <br />
<br />
<br />
3： PROPAGATION_MANDATORY <br />
必须在一个事务中运行。也就是说，他只能被一个父事务调用。否则，他就要抛出异常 <br />
<br />
4： PROPAGATION_REQUIRES_NEW <br />
这个就比较绕口了。 比如我们设计ServiceA<span style="color: #0000cc">.</span>methodA的事务级别为PROPAGATION_REQUIRED，ServiceB<span style="color: #0000cc">.</span>methodB的事务级别为PROPAGATION_REQUIRES_NEW， <br />
那么当执行到ServiceB<span style="color: #0000cc">.</span>methodB的时候，ServiceA<span style="color: #0000cc">.</span>methodA所在的事务就会挂起，ServiceB<span style="color: #0000cc">.</span>methodB会起一个新的事务，等待ServiceB<span style="color: #0000cc">.</span>methodB的事务完成以后， <br />
他才继续执行。他与PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为ServiceB<span style="color: #0000cc">.</span>methodB是新起一个事务，那么就是存在 <br />
两个不同的事务。如果ServiceB<span style="color: #0000cc">.</span>methodB已经提交，那么ServiceA<span style="color: #0000cc">.</span>methodA失败回滚，ServiceB<span style="color: #0000cc">.</span>methodB是不会回滚的。如果ServiceB<span style="color: #0000cc">.</span>methodB失败回滚， <br />
如果他抛出的异常被ServiceA<span style="color: #0000cc">.</span>methodA捕获，ServiceA<span style="color: #0000cc">.</span>methodA事务仍然可能提交。 <br />
<br />
5： PROPAGATION_NOT_SUPPORTED <br />
当前不支持事务。比如ServiceA<span style="color: #0000cc">.</span>methodA的事务级别是PROPAGATION_REQUIRED ，而ServiceB<span style="color: #0000cc">.</span>methodB的事务级别是PROPAGATION_NOT_SUPPORTED ， <br />
那么当执行到ServiceB<span style="color: #0000cc">.</span>methodB时，ServiceA<span style="color: #0000cc">.</span>methodA的事务挂起，而他以非事务的状态运行完，再继续ServiceA<span style="color: #0000cc">.</span>methodA的事务。 <br />
<br />
6： PROPAGATION_NEVER <br />
不能在事务中运行。假设ServiceA<span style="color: #0000cc">.</span>methodA的事务级别是PROPAGATION_REQUIRED， 而ServiceB<span style="color: #0000cc">.</span>methodB的事务级别是PROPAGATION_NEVER ， <br />
那么ServiceB<span style="color: #0000cc">.</span>methodB就要抛出异常了。 <br />
<br />
7： PROPAGATION_NESTED <br />
理解Nested的关键是savepoint。他与PROPAGATION_REQUIRES_NEW的区别是，PROPAGATION_REQUIRES_NEW另起一个事务，将会与他的父事务相互独立， <br />
而Nested的事务和他的父事务是相依的，他的提交是要等和他的父事务一块提交的。也就是说，如果父事务最后回滚，他也要回滚的。 <br />
而Nested事务的好处是他有一个savepoint。 <br />
<span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span> <br />
ServiceA <span style="color: #0000cc">{</span> <br />
<br />
<span style="color: #ff9900">/** <br />
* 事务属性配置为 PROPAGATION_REQUIRED <br />
*/</span> <br />
<span style="color: #0000ff">void</span> methodA<span style="color: #0000cc">(</span><span style="color: #0000cc">)</span> <span style="color: #0000cc">{</span> <br />
<span style="color: #0000ff">try</span> <span style="color: #0000cc">{</span> <br />
<span style="color: #ff9900">//savepoint <br />
</span><br />
ServiceB<span style="color: #0000cc">.</span>methodB<span style="color: #0000cc">(</span><span style="color: #0000cc">)</span><span style="color: #0000cc">;</span> <span style="color: #ff9900">//PROPAGATION_NESTED 级别 <br />
</span><br />
<span style="color: #0000cc">}</span> <span style="color: #0000ff">catch</span> <span style="color: #0000cc">(</span>SomeException<span style="color: #0000cc">)</span> <span style="color: #0000cc">{</span> <br />
<span style="color: #ff9900">// 执行其他业务, 如 ServiceC.methodC(); <br />
</span><br />
<span style="color: #0000cc">}</span> <br />
<span style="color: #0000cc">}</span> <br />
<br />
<span style="color: #0000cc">}</span> <br />
<span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span> <br />
也就是说ServiceB<span style="color: #0000cc">.</span>methodB失败回滚，那么ServiceA<span style="color: #0000cc">.</span>methodA也会回滚到savepoint点上，ServiceA<span style="color: #0000cc">.</span>methodA可以选择另外一个分支，比如 <br />
ServiceC<span style="color: #0000cc">.</span>methodC，继续执行，来尝试完成自己的事务。 <br />
但是这个事务并没有在EJB标准中定义。 <br />
<br />
二、Isolation <span style="color: #ff0000">Level</span><span style="color: #0000cc">(</span>事务隔离等级<span style="color: #0000cc">)</span><span style="color: #0000cc">:</span> <br />
1、Serializable：最严格的级别，事务串行执行，资源消耗最大； <br />
2、REPEATABLE READ：保证了一个事务不会修改已经由另一个事务读取但未提交（回滚）的数据。避免了&#8220;脏读取&#8221;和&#8220;不可重复读取&#8221;的情况，但是带来了更多的性能损失。 <br />
3、READ COMMITTED<span style="color: #0000cc">:</span>大多数主流数据库的默认事务等级，保证了一个事务不会读到另一个并行事务已修改但未提交的数据，避免了&#8220;脏读取&#8221;。该级别适用于大多数系统。 <br />
4、Read Uncommitted：保证了读取过程中不会读取到非法数据。隔离级别在于处理多事务的并发问题。 <br />
我们知道并行可以提高数据库的吞吐量和效率，但是并不是所有的并发事务都可以并发运行，这需要查看数据库教材的可串行化条件判断了。 <br />
这里就不阐述。 <br />
我们首先说并发中可能发生的3中不讨人喜欢的事情 <br />
1： <span style="color: #ff0000">Dirty</span> reads<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>读脏数据。也就是说，比如事务A的未提交（还依然缓存）的数据被事务B读走，如果事务A失败回滚，会导致事务B所读取的的数据是错误的。 <br />
2： non<span style="color: #0000cc">-</span>repeatable reads<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>数据不可重复读。比如事务A中两处读取数据<span style="color: #0000cc">-</span>total<span style="color: #0000cc">-</span>的值。在第一读的时候，total是100，然后事务B就把total的数据改成200，事务A再读一次，结果就发现，total竟然就变成200了，造成事务A数据混乱。 <br />
3： phantom reads<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>幻象读数据，这个和non<span style="color: #0000cc">-</span>repeatable reads相似，也是同一个事务中多次读不一致的问题。但是non<span style="color: #0000cc">-</span>repeatable reads的不一致是因为他所要取的数据集被改变了（比如total的数据），但是phantom reads所要读的数据的不一致却不是他所要读的数据集改变，而是他的条件数据集改变。比如Select account<span style="color: #0000cc">.</span><span style="color: #ff0000">id</span> where account<span style="color: #0000cc">.</span><span style="color: #ff0000">name</span><span style="color: #0000cc">=</span><span style="color: #ff00ff">"ppgogo*"</span><span style="color: #0000cc">,</span>第一次读去了6个符合条件的id，第二次读取的时候，由于事务b把一个帐号的名字由<span style="color: #ff00ff">"dd"</span>改成<span style="color: #ff00ff">"ppgogo1"</span>，结果取出来了7个数据。 <span style="color: #ff0000">Dirty</span> reads non<span style="color: #0000cc">-</span>repeatable reads phantom reads <br />
<span style="color: #ff0000">Serializable</span> 不会 不会 不会 <br />
REPEATABLE <span style="color: #ff0000">READ</span> 不会 不会 会 <br />
<span style="color: #ff0000">READ</span> COMMITTED 不会 会 会 <br />
<span style="color: #ff0000">Read</span> Uncommitted 会 会 会 <br />
<br />
<br />
<br />
<br />
<br />
三、readOnly <br />
事务属性中的readOnly标志表示对应的事务应该被最优化为只读事务。<br />
<br />
这是一个最优化提示。在一些情况下，一些事务策略能够起到显著的最优化效果，例如在使用Object<span style="color: #0000cc">/</span>Relational映射工具（如：Hibernate或TopLink）时避免dirty checking（试图&#8220;刷新&#8221;）。<br />
<br />
四、Timeout <br />
<br />
在事务属性中还有定义&#8220;timeout&#8221;值的选项，指定事务超时为几秒。在JTA中，这将被简单地传递到J2EE服务器的事务协调程序，并据此得到相应的解释。<br />
</span></code></p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/319595.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-04-28 14:30 <a href="http://www.blogjava.net/freeman1984/archive/2010/04/28/319595.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring事务的传播行为和隔离级别 </title><link>http://www.blogjava.net/freeman1984/archive/2010/04/28/319596.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Wed, 28 Apr 2010 06:30:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2010/04/28/319596.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/319596.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2010/04/28/319596.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/319596.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/319596.html</trackback:ping><description><![CDATA[<p style="line-height: 150%; margin: 5px">转载自：http://blog.chinaunix.net/u1/55983/showart_2091761.html<code><span style="color: #000000"><br />
7个传播行为，4个隔离级别， <br />
<br />
Spring事务的传播行为和隔离级别<span style="color: #0000cc">[</span><span style="color: #ff0000">transaction</span> behavior <span style="color: #ff0000">and</span> isolated <span style="color: #ff0000">level</span><span style="color: #0000cc">]</span>2007<span style="color: #0000cc">-</span>08<span style="color: #0000cc">-</span>01 16<span style="color: #0000cc">:</span>33事务的传播行为和隔离级别<span style="color: #0000cc">[</span><span style="color: #ff0000">transaction</span> behavior <span style="color: #ff0000">and</span> isolated <span style="color: #ff0000">level</span><span style="color: #0000cc">]</span><br />
<br />
Spring中事务的定义：<br />
一、Propagation ：<br />
　　key属性确定代理应该给哪个方法增加事务行为。这样的属性最重要的部份是传播行为。有以下选项可供使用：<br />
PROPAGATION_REQUIRED<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>支持当前事务，如果当前没有事务，就新建一个事务。这是最常见的选择。 <br />
PROPAGATION_SUPPORTS<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>支持当前事务，如果当前没有事务，就以非事务方式执行。 <br />
PROPAGATION_MANDATORY<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>支持当前事务，如果当前没有事务，就抛出异常。 <br />
PROPAGATION_REQUIRES_NEW<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>新建事务，如果当前存在事务，把当前事务挂起。 <br />
PROPAGATION_NOT_SUPPORTED<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>以非事务方式执行操作，如果当前存在事务，就把当前事务挂起。 <br />
PROPAGATION_NEVER<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>以非事务方式执行，如果当前存在事务，则抛出异常。 <br />
<br />
很多人看到事务的传播行为属性都不甚了解，我昨晚看了j2ee without ejb的时候，看到这里也不了解，甚至重新翻起数据库系统的教材书，但是也没有找到对这个的分析。今天搜索，找到一篇极好的分析文章，虽然这篇文章是重点分析PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRED_NESTED的<br />
<span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><span style="color: #0000cc">=</span><br />
&nbsp;&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
解惑 <span style="color: #ff0000">spring</span> 嵌套事务 <br />
<span style="color: #ff9900">/** <br />
* @date 2006-11-24 <br />
* @note 转载自http://www.javaeye.com/topic/35907?page=1<br />
*/</span> <br />
<span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span>TransactionDefinition 接口定义<span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><br />
<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Support a current transaction, create a new one if none exists. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Analogous to EJB transaction attribute of the same name. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* <br />
This is typically the default setting of a transaction definition. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">int</span> PROPAGATION_REQUIRED <span style="color: #0000cc">=</span> 0<span style="color: #0000cc">;</span> <br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Support a current transaction, execute non-transactionally if none exists. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Analogous to EJB transaction attribute of the same name. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* <br />
<br />
Note: For transaction managers with transaction synchronization, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* PROPAGATION_SUPPORTS is slightly different from no transaction at all, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* as it defines a transaction scopp that synchronization will apply for. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* As a consequence, the same resources (JDBC Connection, Hibernate Session, etc) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* will be shared for the entire specified scope. Note that this depends on <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* the actual synchronization configuration of the transaction manager. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* @see org.springframework.transaction.support.AbstractPlatformTransactionManager#setTransactionSynchronization <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">int</span> PROPAGATION_SUPPORTS <span style="color: #0000cc">=</span> 1<span style="color: #0000cc">;</span> <br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Support a current transaction, throw an exception if none exists. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Analogous to EJB transaction attribute of the same name. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">int</span> PROPAGATION_MANDATORY <span style="color: #0000cc">=</span> 2<span style="color: #0000cc">;</span> <br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Create a new transaction, suspend the current transaction if one exists. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Analogous to EJB transaction attribute of the same name. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* <br />
<br />
Note: Actual transaction suspension will not work on out-of-the-box <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* on all transaction managers. This in particular applies to JtaTransactionManager, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* which requires the javax.transaction.TransactionManager to be <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* made available it to it (which is server-specific in standard J2EE). <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">int</span> PROPAGATION_REQUIRES_NEW <span style="color: #0000cc">=</span> 3<span style="color: #0000cc">;</span> <br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Execute non-transactionally, suspend the current transaction if one exists. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Analogous to EJB transaction attribute of the same name. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* <br />
<br />
Note: Actual transaction suspension will not work on out-of-the-box <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* on all transaction managers. This in particular applies to JtaTransactionManager, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* which requires the javax.transaction.TransactionManager to be <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* made available it to it (which is server-specific in standard J2EE). <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* @see org.springframework.transaction.jta.JtaTransactionManager#setTransactionManager <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">int</span> PROPAGATION_NOT_SUPPORTED <span style="color: #0000cc">=</span> 4<span style="color: #0000cc">;</span> <br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Execute non-transactionally, throw an exception if a transaction exists. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Analogous to EJB transaction attribute of the same name. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">int</span> PROPAGATION_NEVER <span style="color: #0000cc">=</span> 5<span style="color: #0000cc">;</span> <br />
&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Execute within a nested transaction if a current transaction exists, <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* behave like PROPAGATION_REQUIRED else. There is no analogous feature in EJB. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* <br />
<br />
Note: Actual creation of a nested transaction will only work on specific <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* transaction managers. Out of the box, this only applies to the JDBC <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* DataSourceTransactionManager when working on a JDBC 3.0 driver. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* Some JTA providers might support nested transactions as well. <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* @see org.springframework.jdbc.datasource.DataSourceTransactionManager <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">int</span> PROPAGATION_NESTED <span style="color: #0000cc">=</span> 6<span style="color: #0000cc">;</span> <br />
<br />
<span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><br />
在这篇文章里，他用两个嵌套的例子辅助分析，我这里直接引用了。<br />
<span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span>sample<span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><br />
ServiceA <span style="color: #0000cc">{</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* 事务属性配置为 PROPAGATION_REQUIRED <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">void</span> methodA<span style="color: #0000cc">(</span><span style="color: #0000cc">)</span> <span style="color: #0000cc">{</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ServiceB<span style="color: #0000cc">.</span>methodB<span style="color: #0000cc">(</span><span style="color: #0000cc">)</span><span style="color: #0000cc">;</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000cc">}</span> <br />
&nbsp;&nbsp;<br />
<span style="color: #0000cc">}</span> <br />
&nbsp;&nbsp;<br />
ServiceB <span style="color: #0000cc">{</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #ff9900">/** <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;* 事务属性配置为 PROPAGATION_REQUIRED <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000ff">void</span> methodB<span style="color: #0000cc">(</span><span style="color: #0000cc">)</span> <span style="color: #0000cc">{</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000cc">}</span> <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
<span style="color: #0000cc">}</span> <br />
<span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><br />
1： PROPAGATION_REQUIRED <br />
加入当前正要执行的事务不在另外一个事务里，那么就起一个新的事务 <br />
比如说，ServiceB<span style="color: #0000cc">.</span>methodB的事务级别定义为PROPAGATION_REQUIRED<span style="color: #0000cc">,</span> 那么由于执行ServiceA<span style="color: #0000cc">.</span>methodA的时候， <br />
ServiceA<span style="color: #0000cc">.</span>methodA已经起了事务，这时调用ServiceB<span style="color: #0000cc">.</span>methodB，ServiceB<span style="color: #0000cc">.</span>methodB看到自己已经运行在ServiceA<span style="color: #0000cc">.</span>methodA <br />
的事务内部，就不再起新的事务。而假如ServiceA<span style="color: #0000cc">.</span>methodA运行的时候发现自己没有在事务中，他就会为自己分配一个事务。 <br />
这样，在ServiceA<span style="color: #0000cc">.</span>methodA或者在ServiceB<span style="color: #0000cc">.</span>methodB内的任何地方出现异常，事务都会被回滚。即使ServiceB<span style="color: #0000cc">.</span>methodB的事务已经被 <br />
提交，但是ServiceA<span style="color: #0000cc">.</span>methodA在接下来fail要回滚，ServiceB<span style="color: #0000cc">.</span>methodB也要回滚 <br />
<br />
2： PROPAGATION_SUPPORTS <br />
如果当前在事务中，即以事务的形式运行，如果当前不再一个事务中，那么就以非事务的形式运行 <br />
<br />
<br />
3： PROPAGATION_MANDATORY <br />
必须在一个事务中运行。也就是说，他只能被一个父事务调用。否则，他就要抛出异常 <br />
<br />
4： PROPAGATION_REQUIRES_NEW <br />
这个就比较绕口了。 比如我们设计ServiceA<span style="color: #0000cc">.</span>methodA的事务级别为PROPAGATION_REQUIRED，ServiceB<span style="color: #0000cc">.</span>methodB的事务级别为PROPAGATION_REQUIRES_NEW， <br />
那么当执行到ServiceB<span style="color: #0000cc">.</span>methodB的时候，ServiceA<span style="color: #0000cc">.</span>methodA所在的事务就会挂起，ServiceB<span style="color: #0000cc">.</span>methodB会起一个新的事务，等待ServiceB<span style="color: #0000cc">.</span>methodB的事务完成以后， <br />
他才继续执行。他与PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为ServiceB<span style="color: #0000cc">.</span>methodB是新起一个事务，那么就是存在 <br />
两个不同的事务。如果ServiceB<span style="color: #0000cc">.</span>methodB已经提交，那么ServiceA<span style="color: #0000cc">.</span>methodA失败回滚，ServiceB<span style="color: #0000cc">.</span>methodB是不会回滚的。如果ServiceB<span style="color: #0000cc">.</span>methodB失败回滚， <br />
如果他抛出的异常被ServiceA<span style="color: #0000cc">.</span>methodA捕获，ServiceA<span style="color: #0000cc">.</span>methodA事务仍然可能提交。 <br />
<br />
5： PROPAGATION_NOT_SUPPORTED <br />
当前不支持事务。比如ServiceA<span style="color: #0000cc">.</span>methodA的事务级别是PROPAGATION_REQUIRED ，而ServiceB<span style="color: #0000cc">.</span>methodB的事务级别是PROPAGATION_NOT_SUPPORTED ， <br />
那么当执行到ServiceB<span style="color: #0000cc">.</span>methodB时，ServiceA<span style="color: #0000cc">.</span>methodA的事务挂起，而他以非事务的状态运行完，再继续ServiceA<span style="color: #0000cc">.</span>methodA的事务。 <br />
<br />
6： PROPAGATION_NEVER <br />
不能在事务中运行。假设ServiceA<span style="color: #0000cc">.</span>methodA的事务级别是PROPAGATION_REQUIRED， 而ServiceB<span style="color: #0000cc">.</span>methodB的事务级别是PROPAGATION_NEVER ， <br />
那么ServiceB<span style="color: #0000cc">.</span>methodB就要抛出异常了。 <br />
<br />
7： PROPAGATION_NESTED <br />
理解Nested的关键是savepoint。他与PROPAGATION_REQUIRES_NEW的区别是，PROPAGATION_REQUIRES_NEW另起一个事务，将会与他的父事务相互独立， <br />
而Nested的事务和他的父事务是相依的，他的提交是要等和他的父事务一块提交的。也就是说，如果父事务最后回滚，他也要回滚的。 <br />
而Nested事务的好处是他有一个savepoint。 <br />
<span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span> <br />
ServiceA <span style="color: #0000cc">{</span> <br />
<br />
<span style="color: #ff9900">/** <br />
* 事务属性配置为 PROPAGATION_REQUIRED <br />
*/</span> <br />
<span style="color: #0000ff">void</span> methodA<span style="color: #0000cc">(</span><span style="color: #0000cc">)</span> <span style="color: #0000cc">{</span> <br />
<span style="color: #0000ff">try</span> <span style="color: #0000cc">{</span> <br />
<span style="color: #ff9900">//savepoint <br />
</span><br />
ServiceB<span style="color: #0000cc">.</span>methodB<span style="color: #0000cc">(</span><span style="color: #0000cc">)</span><span style="color: #0000cc">;</span> <span style="color: #ff9900">//PROPAGATION_NESTED 级别 <br />
</span><br />
<span style="color: #0000cc">}</span> <span style="color: #0000ff">catch</span> <span style="color: #0000cc">(</span>SomeException<span style="color: #0000cc">)</span> <span style="color: #0000cc">{</span> <br />
<span style="color: #ff9900">// 执行其他业务, 如 ServiceC.methodC(); <br />
</span><br />
<span style="color: #0000cc">}</span> <br />
<span style="color: #0000cc">}</span> <br />
<br />
<span style="color: #0000cc">}</span> <br />
<span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span><span style="color: #0000cc">*</span> <br />
也就是说ServiceB<span style="color: #0000cc">.</span>methodB失败回滚，那么ServiceA<span style="color: #0000cc">.</span>methodA也会回滚到savepoint点上，ServiceA<span style="color: #0000cc">.</span>methodA可以选择另外一个分支，比如 <br />
ServiceC<span style="color: #0000cc">.</span>methodC，继续执行，来尝试完成自己的事务。 <br />
但是这个事务并没有在EJB标准中定义。 <br />
<br />
二、Isolation <span style="color: #ff0000">Level</span><span style="color: #0000cc">(</span>事务隔离等级<span style="color: #0000cc">)</span><span style="color: #0000cc">:</span> <br />
1、Serializable：最严格的级别，事务串行执行，资源消耗最大； <br />
2、REPEATABLE READ：保证了一个事务不会修改已经由另一个事务读取但未提交（回滚）的数据。避免了&#8220;脏读取&#8221;和&#8220;不可重复读取&#8221;的情况，但是带来了更多的性能损失。 <br />
3、READ COMMITTED<span style="color: #0000cc">:</span>大多数主流数据库的默认事务等级，保证了一个事务不会读到另一个并行事务已修改但未提交的数据，避免了&#8220;脏读取&#8221;。该级别适用于大多数系统。 <br />
4、Read Uncommitted：保证了读取过程中不会读取到非法数据。隔离级别在于处理多事务的并发问题。 <br />
我们知道并行可以提高数据库的吞吐量和效率，但是并不是所有的并发事务都可以并发运行，这需要查看数据库教材的可串行化条件判断了。 <br />
这里就不阐述。 <br />
我们首先说并发中可能发生的3中不讨人喜欢的事情 <br />
1： <span style="color: #ff0000">Dirty</span> reads<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>读脏数据。也就是说，比如事务A的未提交（还依然缓存）的数据被事务B读走，如果事务A失败回滚，会导致事务B所读取的的数据是错误的。 <br />
2： non<span style="color: #0000cc">-</span>repeatable reads<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>数据不可重复读。比如事务A中两处读取数据<span style="color: #0000cc">-</span>total<span style="color: #0000cc">-</span>的值。在第一读的时候，total是100，然后事务B就把total的数据改成200，事务A再读一次，结果就发现，total竟然就变成200了，造成事务A数据混乱。 <br />
3： phantom reads<span style="color: #0000cc">-</span><span style="color: #0000cc">-</span>幻象读数据，这个和non<span style="color: #0000cc">-</span>repeatable reads相似，也是同一个事务中多次读不一致的问题。但是non<span style="color: #0000cc">-</span>repeatable reads的不一致是因为他所要取的数据集被改变了（比如total的数据），但是phantom reads所要读的数据的不一致却不是他所要读的数据集改变，而是他的条件数据集改变。比如Select account<span style="color: #0000cc">.</span><span style="color: #ff0000">id</span> where account<span style="color: #0000cc">.</span><span style="color: #ff0000">name</span><span style="color: #0000cc">=</span><span style="color: #ff00ff">"ppgogo*"</span><span style="color: #0000cc">,</span>第一次读去了6个符合条件的id，第二次读取的时候，由于事务b把一个帐号的名字由<span style="color: #ff00ff">"dd"</span>改成<span style="color: #ff00ff">"ppgogo1"</span>，结果取出来了7个数据。 <span style="color: #ff0000">Dirty</span> reads non<span style="color: #0000cc">-</span>repeatable reads phantom reads <br />
<span style="color: #ff0000">Serializable</span> 不会 不会 不会 <br />
REPEATABLE <span style="color: #ff0000">READ</span> 不会 不会 会 <br />
<span style="color: #ff0000">READ</span> COMMITTED 不会 会 会 <br />
<span style="color: #ff0000">Read</span> Uncommitted 会 会 会 <br />
<br />
<br />
<br />
<br />
<br />
三、readOnly <br />
事务属性中的readOnly标志表示对应的事务应该被最优化为只读事务。<br />
<br />
这是一个最优化提示。在一些情况下，一些事务策略能够起到显著的最优化效果，例如在使用Object<span style="color: #0000cc">/</span>Relational映射工具（如：Hibernate或TopLink）时避免dirty checking（试图&#8220;刷新&#8221;）。<br />
<br />
四、Timeout <br />
<br />
在事务属性中还有定义&#8220;timeout&#8221;值的选项，指定事务超时为几秒。在JTA中，这将被简单地传递到J2EE服务器的事务协调程序，并据此得到相应的解释。<br />
</span></code></p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/319596.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2010-04-28 14:30 <a href="http://www.blogjava.net/freeman1984/archive/2010/04/28/319596.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate annoation (二创建表)</title><link>http://www.blogjava.net/freeman1984/archive/2009/11/02/300707.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 02 Nov 2009 06:58:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2009/11/02/300707.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/300707.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2009/11/02/300707.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/300707.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/300707.html</trackback:ping><description><![CDATA[<p>为了追踪hibernate的信息 &lt;property name="hibernate.show_sql"&gt;true&lt;/property&gt;</p>
<p>&nbsp;新建User类:</p>
<p><strong></strong>&nbsp;</p>
<div class="quote_div">@Entity <br />
@Table(name="E_USER",uniqueConstraints={ <br />
@UniqueConstraint(columnNames={"yahoo"}) <br />
}) <br />
public class User { <br />
<br />
private int id; <br />
private String yahoo; //昵称唯一<br />
<br />
@Id <br />
@GeneratedValue(strategy=GenerationType.AUTO) <br />
public int getId() { <br />
return id; <br />
} <br />
public void setId(int id) { <br />
this.id = id; <br />
} <br />
public String getYahoo() { <br />
return yahoo; <br />
} <br />
public void setYahoo(String yahoo) { <br />
this.yahoo = yahoo; <br />
} <br />
<br />
}</div>
<p>&nbsp;创建表 首先在hibernate.cfg.xml里配置&lt;mapping class="com.eric.po.User"/&gt;说明：使用annoation同样可以接受.hbm.xml文件</p>
<p>&nbsp;1，以手动创建 </p>
<p>&nbsp;&nbsp; DROP TABLE IF EXISTS `e_user`;<br />
CREATE TABLE `e_user` (<br />
&nbsp; `id` int(11) NOT NULL auto_increment,<br />
&nbsp; `yahoo` varchar(255) default NULL,<br />
&nbsp; PRIMARY KEY&nbsp; (`id`),<br />
&nbsp; UNIQUE KEY `yahoo` (`yahoo`)<br />
) ENGINE=InnoDB DEFAULT CHARSET=utf8;</p>
<p>&nbsp;2，使用&lt;property name="hbm2ddl.auto"&gt;create&lt;/property&gt;属性来自动创建</p>
<p>&nbsp;3，SchemaExport ： new SchemaExport(new AnnotationConfiguration().configure()).create(true,true);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; create(true,true)：两个参数：&nbsp;&nbsp;&nbsp; </p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://coffeef.javaeye.com/admin/blogs/452062#"><img alt="复制代码" src="http://coffeef.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>*&nbsp;</span><span class="annotation">@param</span><span>&nbsp;script&nbsp;print&nbsp;the&nbsp;DDL&nbsp;to&nbsp;the&nbsp;console &nbsp;&nbsp;</span></span></li>
    <li><span>*&nbsp;</span><span class="annotation">@param</span><span>&nbsp;export&nbsp;export&nbsp;the&nbsp;script&nbsp;to&nbsp;the&nbsp;database&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">* @param script print the DDL to the console
* @param export export the script to the database</pre>
<p>&nbsp;&nbsp; hibernate建表语句：</p>
<p>&nbsp; drop table if exists E_USER<br />
&nbsp;create table E_USER (id integer not null auto_increment, yahoo varchar(255), primary key (id), unique (yahoo))</p>
 <img src ="http://www.blogjava.net/freeman1984/aggbug/300707.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2009-11-02 14:58 <a href="http://www.blogjava.net/freeman1984/archive/2009/11/02/300707.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate annoation (一加载)</title><link>http://www.blogjava.net/freeman1984/archive/2009/11/02/300708.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 02 Nov 2009 06:58:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2009/11/02/300708.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/300708.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2009/11/02/300708.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/300708.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/300708.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
<p>&nbsp;</p>
<p>一,配置文件加载</p>
<p>&nbsp;1，Configuration</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;如果不是annoation则可以使用Configuration configuration = new Configuration()；</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用annoation则可以使用Configuration configuration = new AnnotationConfiguration();</p>
<p>&nbsp;&nbsp;2，加载，使用onfiguration的configure方法根据方法参数可以有一下几种加载方式：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（1） configure()；</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;吃方法会去classpath下寻找我们的配置文件</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 其实调用了configure( "/hibernate.cfg.xml" );也就是 configure(String resource)；方法</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（2） configure(String resource)；</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 最常用方的方法，其实调用了doConfigure(InputStream stream, String resourceName)；</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 说明一点内部代码：</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ConfigHelper.getResourceAsStream( resource );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://coffeef.javaeye.com/admin/blogs/452011#"><img alt="复制代码" src="http://coffeef.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>String&nbsp;stripped&nbsp;=&nbsp;resource.startsWith(</span><span class="string">"/"</span><span>)&nbsp;? &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;resource.substring(</span><span class="number">1</span><span>)&nbsp;:&nbsp;resource; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>InputStream&nbsp;stream&nbsp;=&nbsp;</span><span class="keyword">null</span><span>; &nbsp;&nbsp;</span></span></li>
    <li><span>ClassLoader&nbsp;classLoader&nbsp;=&nbsp;Thread.currentThread().getContextClassLoader(); &nbsp;&nbsp;</span></li>
    <li><span class="keyword">if</span><span>&nbsp;(classLoader!=</span><span class="keyword">null</span><span>)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;stream&nbsp;=&nbsp;classLoader.getResourceAsStream(&nbsp;stripped&nbsp;); &nbsp;&nbsp;</span></li>
    <li><span>} &nbsp;&nbsp;</span></li>
    <li><span class="keyword">if</span><span>&nbsp;(&nbsp;stream&nbsp;==&nbsp;</span><span class="keyword">null</span><span>&nbsp;)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;stream&nbsp;=&nbsp;Environment.</span><span class="keyword">class</span><span>.getResourceAsStream(&nbsp;resource&nbsp;); &nbsp;&nbsp;</span></span></li>
    <li><span>} &nbsp;&nbsp;</span></li>
    <li><span class="keyword">if</span><span>&nbsp;(&nbsp;stream&nbsp;==&nbsp;</span><span class="keyword">null</span><span>&nbsp;)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;stream&nbsp;=&nbsp;Environment.</span><span class="keyword">class</span><span>.getClassLoader().getResourceAsStream(&nbsp;stripped&nbsp;); &nbsp;&nbsp;</span></span></li>
    <li><span>} &nbsp;&nbsp;</span></li>
    <li><span class="keyword">if</span><span>&nbsp;(&nbsp;stream&nbsp;==&nbsp;</span><span class="keyword">null</span><span>&nbsp;)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;HibernateException(&nbsp;resource&nbsp;+&nbsp;</span><span class="string">"&nbsp;not&nbsp;found"</span><span>&nbsp;); &nbsp;&nbsp;</span></span></li>
    <li><span>} &nbsp;&nbsp;</span></li>
    <li><span class="keyword">return</span><span>&nbsp;stream; &nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">		String stripped = resource.startsWith("/") ?
resource.substring(1) : resource;
InputStream stream = null;
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader!=null) {
stream = classLoader.getResourceAsStream( stripped );
}
if ( stream == null ) {
stream = Environment.class.getResourceAsStream( resource );
}
if ( stream == null ) {
stream = Environment.class.getClassLoader().getResourceAsStream( stripped );
}
if ( stream == null ) {
throw new HibernateException( resource + " not found" );
}
return stream;
</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 第一行高数我们"/hibernate.cfg.xml" 可以去掉前面的&#8220;/&#8221;其中调用了Thread.currentThread().getContextClassLoader();一般也就是我们的AppClassLoader </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 由stream = Environment.class.getResourceAsStream( resource );可以看出我们的"/hibernate.cfg.xml同样可以放在与和Environment同样的目录 具体到我们的代码里面在使用（3），（4），（5）时可以放在加载 类的包内或其他</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（3） configure(URL url)；</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doConfigure( url.openStream(), url.toString() );调用（5）</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（4）&nbsp;configure(File configFile)；</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; doConfigure( new FileInputStream( configFile ), configFile.toString() );调用（5）</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（5） doConfigure(InputStream stream, String resourceName)；</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 使用dom4j解析文件为Document然后</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlHelper.createSAXReader( resourceName, errors, entityResolver )<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.read( new InputSource( stream ) );</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 掉用（6）</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;（6） configure(Document document)；</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在这个方法里会解析所有配置信息和mapping类或者hb文件</p>
 <img src ="http://www.blogjava.net/freeman1984/aggbug/300708.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2009-11-02 14:58 <a href="http://www.blogjava.net/freeman1984/archive/2009/11/02/300708.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate annoation (四 lob)</title><link>http://www.blogjava.net/freeman1984/archive/2009/11/02/300705.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 02 Nov 2009 06:57:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2009/11/02/300705.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/300705.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2009/11/02/300705.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/300705.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/300705.html</trackback:ping><description><![CDATA[<p>hiberante sql映射对应</p>
<p>&nbsp; </p>
<table style="width: 100%; text-align: left" cellspacing="2" cellpadding="2" border="1">
    <tbody>
        <tr>
            <td style="background-color: #cccccc"><small><span style="font-size: x-small"><span style="font-size: xx-small">Java数据类型</span></span></small></td>
            <td style="background-color: #cccccc"><small><span style="font-size: x-small"><span style="font-size: xx-small">Hibernate数据类型</span></span></small></td>
            <td style="background-color: #cccccc"><small><span style="font-size: x-small"><span style="font-size: xx-small">标准SQL数据类型<br />
            (PS:对于不同的DB可能有所差异)</span></span></small></td>
        </tr>
        <tr>
            <td>byte、java.lang.Byte</td>
            <td>byte</td>
            <td>TINYINT</td>
        </tr>
        <tr>
            <td>short、java.lang.Short</td>
            <td>short</td>
            <td>SMALLINT</td>
        </tr>
        <tr>
            <td>int、java.lang.Integer</td>
            <td>integer</td>
            <td>INGEGER</td>
        </tr>
        <tr>
            <td>long、java.lang.Long</td>
            <td>long</td>
            <td>BIGINT</td>
        </tr>
        <tr>
            <td>float、java.lang.Float</td>
            <td>float</td>
            <td>FLOAT</td>
        </tr>
        <tr>
            <td>double、java.lang.Double</td>
            <td>double</td>
            <td>DOUBLE</td>
        </tr>
        <tr>
            <td>java.math.BigDecimal</td>
            <td>big_decimal</td>
            <td>NUMERIC</td>
        </tr>
        <tr>
            <td>char、java.lang.Character</td>
            <td>character</td>
            <td>CHAR(1)</td>
        </tr>
        <tr>
            <td>boolean、java.lang.Boolean</td>
            <td>boolean</td>
            <td>BIT</td>
        </tr>
        <tr>
            <td>java.lang.String</td>
            <td>string</td>
            <td>VARCHAR</td>
        </tr>
        <tr>
            <td>boolean、java.lang.Boolean</td>
            <td>yes_no</td>
            <td>CHAR(1)('Y'或'N')</td>
        </tr>
        <tr>
            <td>boolean、java.lang.Boolean</td>
            <td>true_false</td>
            <td>CHAR(1)('Y'或'N')</td>
        </tr>
        <tr>
            <td>java.util.Date、java.sql.Date</td>
            <td>date</td>
            <td>DATE</td>
        </tr>
        <tr>
            <td>java.util.Date、java.sql.Time</td>
            <td>time</td>
            <td>TIME</td>
        </tr>
        <tr>
            <td>java.util.Date、java.sql.Timestamp</td>
            <td>timestamp</td>
            <td>TIMESTAMP</td>
        </tr>
        <tr>
            <td>java.util.Calendar</td>
            <td>calendar</td>
            <td>TIMESTAMP</td>
        </tr>
        <tr>
            <td>java.util.Calendar</td>
            <td>calendar_date</td>
            <td>DATE</td>
        </tr>
        <tr>
            <td>byte[]</td>
            <td>binary</td>
            <td>VARBINARY、BLOB</td>
        </tr>
        <tr>
            <td>java.lang.String</td>
            <td>text</td>
            <td>CLOB</td>
        </tr>
        <tr>
            <td>java.io.Serializable</td>
            <td>serializable</td>
            <td>VARBINARY、BLOB</td>
        </tr>
        <tr>
            <td>java.sql.Clob</td>
            <td>clob</td>
            <td>CLOB</td>
        </tr>
        <tr>
            <td>java.sql.Blob</td>
            <td>blob</td>
            <td>BLOB</td>
        </tr>
        <tr>
            <td>java.lang.Class</td>
            <td>class</td>
            <td>VARCHAR</td>
        </tr>
        <tr>
            <td>java.util.Locale</td>
            <td>locale</td>
            <td>VARCHAR</td>
        </tr>
        <tr>
            <td>java.util.TimeZone</td>
            <td>timezone</td>
            <td>VARCHAR</td>
        </tr>
        <tr>
            <td>java.util.Currency</td>
            <td>currency</td>
            <td>VARCHAR</td>
        </tr>
    </tbody>
</table>
<p>&nbsp;</p>
<p>一，针对大字段也就是 colb，blob</p>
<p>&nbsp;在hibernate annoation里面可以如下使用:</p>
<p>&nbsp; @Lob<br />
&nbsp;public String getC() {<br />
&nbsp;&nbsp;return c;<br />
&nbsp;}<br />
&nbsp;@Lob<br />
&nbsp;public byte[] getB() {<br />
&nbsp;&nbsp;return b;<br />
&nbsp;}</p>
<p>&nbsp;<span style="font-family: Courier New">java.sql.Clob</span>, <tt class="classname">Character[]</tt>, <tt class="classname">char[]</tt> and java.lang.<tt class="classname">String</tt>&nbsp;会被映射为 Clob. <tt class="classname">java.sql.Blob</tt>, <tt class="classname">Byte[]</tt>, <tt class="classname">byte[] </tt>and serializable 会被映射为Blob.</p>
<p>&nbsp; 当然我们可以使用正对不同的数据库使用数据库原始类型例如 mysql：使用@Column&nbsp;&nbsp; (columnDefinition="longtext")(不推荐使用这种 防止有些数据库的对clob和blob的不支持)</p>
<p>&nbsp; 对blob也可以不进行任何注释但是在使用的时候会有预想不到的错误 例如 mysql 他会映射为TINYBLOB 其容量为 256 字节&nbsp; 如果加上lob注释 则映射为LONGBLOB 容量为4g，可想而知 相见我的利益篇文章：</p>
<p><a href="http://coffeef.javaeye.com/admin/blogs/443623">http://ericjoe.javaeye.com/admin/blogs/443623</a></p>
<p>则可以映射为数据库对应的clob内省或者blob内型 例如（mysql：b longblob, c longtext）；</p>
<p>存取的时候clob就可以按照string类型来处理 而blob可以以流的形式来处理 例如：</p>
<p>存的时候：</p>
<p>BufferedInputStream in = new BufferedInputStream(new FileInputStream(<br />
&nbsp;&nbsp;&nbsp;&nbsp;new File("d:\\19204.jpg")));<br />
&nbsp;&nbsp;byte[] b = new byte[in.available()];<br />
&nbsp;&nbsp;in.read(b);</p>
<p>bean.setB(b); </p>
<p>in.close();</p>
<p>读取：</p>
<p>Session session = HibernateSessionFactory.getSession();<br />
&nbsp;&nbsp;User user = (User)session.get(User.class, 1);<br />
&nbsp;&nbsp;byte[] b = user.getB();<br />
&nbsp;&nbsp;BufferedOutputStream&nbsp;out = new BufferedOutputStream(new FileOutputStream(<br />
&nbsp;&nbsp;&nbsp;&nbsp;new File("d:\\192041.jpg")));<br />
&nbsp;&nbsp;out.write(b);<br />
&nbsp;&nbsp;out.close();</p>
 <img src ="http://www.blogjava.net/freeman1984/aggbug/300705.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2009-11-02 14:57 <a href="http://www.blogjava.net/freeman1984/archive/2009/11/02/300705.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate annoation (三 id生成器)</title><link>http://www.blogjava.net/freeman1984/archive/2009/11/02/300706.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 02 Nov 2009 06:57:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2009/11/02/300706.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/300706.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2009/11/02/300706.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/300706.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/300706.html</trackback:ping><description><![CDATA[<div class="blog_content">
<p>id生成：<br />
hibernate内不可使用的id生成器可见代码</p>
<p>使用@GeneratedValue<br />
1 正对不同的数据库可以同时使用<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Id<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @GeneratedValue(strategy = GenerationType.AUTO)<br />
2 针对mysql<br />
&nbsp;@Id<br />
&nbsp;@GeneratedValue(strategy = GenerationType.IDENTITY)<br />
3 针对oracle<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @Id<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @GeneratedValue(strategy = GenerationType.SEQUENCE,generator="s_gen")<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @SequenceGenerator(name="s_gen",sequenceName="s_seq")<br />
说明：@GeneratedValue()的strategy属性支持5中id生成器：除上面3中外还有GenerationType.TABLE<br />
2配合使用@GenericGenerator 不单独使用<br />
hibernate内不可使用的id生成器可见代码<br />
GENERATORS.put( "uuid", UUIDHexGenerator.class );<br />
&nbsp;&nbsp;GENERATORS.put( "hilo", TableHiLoGenerator.class );<br />
&nbsp;&nbsp;GENERATORS.put( "assigned", Assigned.class );<br />
&nbsp;&nbsp;GENERATORS.put( "identity", IdentityGenerator.class );<br />
&nbsp;&nbsp;GENERATORS.put( "select", SelectGenerator.class );<br />
&nbsp;&nbsp;GENERATORS.put( "sequence", SequenceGenerator.class );<br />
&nbsp;&nbsp;GENERATORS.put( "seqhilo", SequenceHiLoGenerator.class );<br />
&nbsp;&nbsp;GENERATORS.put( "increment", IncrementGenerator.class );<br />
&nbsp;&nbsp;GENERATORS.put( "foreign", ForeignGenerator.class );<br />
&nbsp;&nbsp;GENERATORS.put( "guid", GUIDGenerator.class );<br />
&nbsp;&nbsp;GENERATORS.put( "uuid.hex", UUIDHexGenerator.class ); &nbsp;// uuid.hex is deprecated<br />
&nbsp;&nbsp;GENERATORS.put( "sequence-identity", SequenceIdentityGenerator.class );<br />
)<br />
如果想要不同的表使用相同的主键生成器，可以把他的generator的name属性设为相同即可<br />
例如：<br />
@GeneratedValue(name="id1")<br />
@GenericGenerator(name="id1",strategy="identity")<br />
<br />
</p>
</div>
&nbsp;
<p>1、native</p>
<p>&nbsp;@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "native")</p>
<p>2、uuid<br />
@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "uuid")</p>
<p>3、hilo</p>
<p>@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "hilo")</p>
<p>4、assigned<br />
@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "assigned")</p>
<p>5、identity</p>
<p>@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "identity")</p>
<p>6、select</p>
<p>@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name="select", strategy="select", parameters = { @Parameter(name = "key", value = "idstoerung") })</p>
<p>7、sequence</p>
<p>Java代码<br />
&nbsp;@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "sequence", parameters = { @Parameter(name = "sequence", value = "seq_payablemoney") })</p>
<p>8、seqhilo</p>
<p>&nbsp; @GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "seqhilo", parameters = { @Parameter(name = "max_lo", value = "5") })</p>
<p>9、increment</p>
<p>Java代码<br />
@GeneratedValue(generator = "paymentableGenerator") @GenericGenerator(name = "paymentableGenerator", strategy = "increment")</p>
<p>&nbsp;</p>
<img src ="http://www.blogjava.net/freeman1984/aggbug/300706.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2009-11-02 14:57 <a href="http://www.blogjava.net/freeman1984/archive/2009/11/02/300706.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate annoation (五 组件)</title><link>http://www.blogjava.net/freeman1984/archive/2009/11/02/300704.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 02 Nov 2009 06:56:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2009/11/02/300704.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/300704.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2009/11/02/300704.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/300704.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/300704.html</trackback:ping><description><![CDATA[<div class="blog_content">
<p>例如:有三个类 A B C&nbsp; 最终要持久化的类是A 而 B C 都作为组件内在与A&nbsp; B,C都要使用@Embeddable标注声明为一个组件</p>
<p>&nbsp;</p>
<p>class A 代码：</p>
<p>&nbsp;</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <img alt="复制代码" src="http://coffeef.javaeye.com/images/icon_copy.gif" /></div>
</div>
<ol class="dp-j">
    <li><span><span class="annotation">@Entry</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;A{ &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;id; &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">private</span><span>&nbsp;B&nbsp;b; &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">private</span><span>&nbsp;C&nbsp;c; &nbsp;&nbsp;</span></span></li>
    <li><span>... &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="keyword">public</span><span>&nbsp;B&nbsp;getB(){ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;... &nbsp;&nbsp;</span></li>
    <li><span>} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="keyword">public</span><span>&nbsp;C&nbsp;getC(){ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>.... &nbsp;&nbsp;</span></li>
    <li><span>} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">@Entry
public class A{
private int id;
private B b;
private C c;
...
public B getB(){
...
}
public C getC(){
....
}
}</pre>
<p>&nbsp;B 包含C</p>
<p>class B</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <img alt="复制代码" src="http://coffeef.javaeye.com/images/icon_copy.gif" /></div>
</div>
<ol class="dp-j">
    <li><span><span class="annotation">@Embeddable</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;&nbsp;</span><span class="keyword">class</span><span>&nbsp;B{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;Stirng&nbsp;bname; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;C&nbsp;c; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;get&nbsp;set.... &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">@Embeddable
public  class B{
private Stirng bname;
private C c;
get set....
}</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>class C</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <img alt="复制代码" src="http://coffeef.javaeye.com/images/icon_copy.gif" /></div>
</div>
<ol class="dp-j">
    <li><span><span class="annotation">@Embeddable</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;C{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;cnam2; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;&nbsp;get&nbsp;set.... &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">@Embeddable
public class C{
private String cnam2;
get set....
}</pre>
<p>&nbsp;持久化后 并没有将C的cnam重复持久化为两个字段如果需要这样则需要：</p>
<p>&nbsp; 在A中使用：</p>
<p>&nbsp;@Enumerated<br />
&nbsp;@AttributeOverrides(<br />
&nbsp;&nbsp;&nbsp;{@AttributeOverride(name="bname",column =&nbsp; @Column(name="cname1") )}<br />
&nbsp;&nbsp;&nbsp;)</p>
<p>这样cname将会再次被颜色为一个字段cnam1</p>
</div>
 <img src ="http://www.blogjava.net/freeman1984/aggbug/300704.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2009-11-02 14:56 <a href="http://www.blogjava.net/freeman1984/archive/2009/11/02/300704.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate annoation (六 复合主键)</title><link>http://www.blogjava.net/freeman1984/archive/2009/11/02/300703.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 02 Nov 2009 06:55:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2009/11/02/300703.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/300703.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2009/11/02/300703.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/300703.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/300703.html</trackback:ping><description><![CDATA[<div class="blog_content">
<p>主键类：定义为@Embeddable</p>
<p>@Embeddable<br />
public class F <font style="background-color: #cce8cf">implements Serializable</font>{//序列化 并且最好<font style="background-color: #cce8cf">override equals()</font> and <font style="background-color: #cce8cf">hashCode()</font></p>
<p>&nbsp;private int id;<br />
&nbsp;private int id2;<br />
&nbsp;public int getId() {<br />
&nbsp;&nbsp;return id;<br />
&nbsp;}<br />
&nbsp;public void setId(int id) {<br />
&nbsp;&nbsp;this.id = id;<br />
&nbsp;}<br />
&nbsp;public int getId2() {<br />
&nbsp;&nbsp;return id2;<br />
&nbsp;}<br />
&nbsp;public void setId2(int id2) {<br />
&nbsp;&nbsp;this.id2 = id2;<br />
&nbsp;}<br />
&nbsp;<br />
}<br />
持久化类：</p>
<p>@Entity<br />
@Table(name="E_USER",uniqueConstraints={<br />
&nbsp;&nbsp;@UniqueConstraint(columnNames={"yahoo"})<br />
&nbsp;&nbsp;})<br />
@IdClass(F.class)//将F作为主键类<br />
public class User {</p>
<p>&nbsp;private int id;<br />
&nbsp;private int id2; </p>
<p>//id id2必须和F中的属性一致<br />
&nbsp;private String yahoo;<br />
&nbsp;@Id<br />
&nbsp;@GeneratedValue(strategy=GenerationType.IDENTITY)</p>
<p>&nbsp;public int getId() {<br />
&nbsp;&nbsp;return id;<br />
&nbsp;}<br />
&nbsp;public void setId(int id) {<br />
&nbsp;&nbsp;this.id = id;<br />
&nbsp;}<br />
&nbsp;@Id<br />
&nbsp;@GeneratedValue(strategy=GenerationType.IDENTITY)<br />
&nbsp;public int getId2() {<br />
&nbsp;&nbsp;return id2;<br />
&nbsp;}<br />
&nbsp;public void setId2(int id2) {<br />
&nbsp;&nbsp;this.id2 = id2;<br />
&nbsp;}<br />
&nbsp;public String getYahoo() {<br />
&nbsp;&nbsp;return yahoo;<br />
&nbsp;}<br />
&nbsp;public void setYahoo(String yahoo) {<br />
&nbsp;&nbsp;this.yahoo = yahoo;<br />
&nbsp;}<br />
&nbsp;<br />
}<br />
<br />
<br />
或者了一种方法：<br />
<br />
使用@EmbeddedId F f;</p>
<p>最终生成sql：(mysql)</p>
<p>create table E_USER (id integer not null, id2 integer not null, yahoo varchar(255), primary key (id, id2), unique (yahoo))</p>
</div>
<img src ="http://www.blogjava.net/freeman1984/aggbug/300703.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2009-11-02 14:55 <a href="http://www.blogjava.net/freeman1984/archive/2009/11/02/300703.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate annoation (八 关联映射)</title><link>http://www.blogjava.net/freeman1984/archive/2009/11/02/300700.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 02 Nov 2009 06:54:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2009/11/02/300700.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/300700.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2009/11/02/300700.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/300700.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/300700.html</trackback:ping><description><![CDATA[<div class="blog_content">
<p>onetoone:单向</p>
<p>1,主键关联：</p>
<p>&nbsp;在关联放使用@OneToOne </p>
<p>sql语句：（类代码见同前面的代码）</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div></div>
<ol class="dp-j"><li><span>create&nbsp;table&nbsp;A&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;aname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;b_id&nbsp;integer,&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></li><li><span>create&nbsp;table&nbsp;B&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;bname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></span></li><li><span>alter&nbsp;table&nbsp;A&nbsp;add&nbsp;index&nbsp;FK41FCD34905&nbsp;(b_id),&nbsp;add&nbsp;constraint&nbsp;FK41FCD34905&nbsp;foreign&nbsp;key&nbsp;(b_id)&nbsp;references&nbsp;B&nbsp;(id)&nbsp;&nbsp;</span> </li></ol></div><pre style="display: none" class="java" name="code">create table A (id integer not null auto_increment, aname varchar(255), b_id integer, primary key (id))
create table B (id integer not null auto_increment, bname varchar(255), primary key (id))
alter table A add index FK41FCD34905 (b_id), add constraint FK41FCD34905 foreign key (b_id) references B (id)
</pre>
<p>可以使用@PrimaryKeyJoinColumn进行关联 </p>
<p>2&nbsp;双向：</p>
<p>在关联方使用&nbsp;</p>
<p>@OneToOne(cascade=CascadeType.ALL)<br />@JoinColumn(name="b")</p>
<p>被关联方使用</p>
<p>@OneToOne(mappedBy="b")</p>
<p>最终sql：</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div></div>
<ol class="dp-j"><li><span>create&nbsp;table&nbsp;A&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;aname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;b&nbsp;integer,&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></li><li><span>create&nbsp;table&nbsp;B&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;bname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></span></li><li><span>alter&nbsp;table&nbsp;A&nbsp;add&nbsp;index&nbsp;FK41FCA54B4F&nbsp;(b),&nbsp;add&nbsp;constraint&nbsp;FK41FCA54B4F&nbsp;foreign&nbsp;key&nbsp;(b)&nbsp;references&nbsp;B&nbsp;(id)&nbsp;&nbsp;</span> </li></ol></div><pre style="display: none" class="java" name="code">create table A (id integer not null auto_increment, aname varchar(255), b integer, primary key (id))
create table B (id integer not null auto_increment, bname varchar(255), primary key (id))
alter table A add index FK41FCA54B4F (b), add constraint FK41FCA54B4F foreign key (b) references B (id)</pre>
<p>如果不写</p>
<p>@OneToOne(mappedBy="b")则会在被关联放也生成一个字段</p>
<p>最终代码:</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div></div>
<ol class="dp-j"><li><span>create&nbsp;table&nbsp;A&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;aname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;i_id&nbsp;integer,&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></li><li><span>create&nbsp;table&nbsp;B&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;bname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;a_id&nbsp;integer,&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></span></li><li><span>alter&nbsp;table&nbsp;A&nbsp;add&nbsp;index&nbsp;FK41FCD6779E&nbsp;(i_id),&nbsp;add&nbsp;constraint&nbsp;FK41FCD6779E&nbsp;foreign&nbsp;key&nbsp;(i_id)&nbsp;references&nbsp;B&nbsp;(id) &nbsp;&nbsp;</span></li><li><span>alter&nbsp;table&nbsp;B&nbsp;add&nbsp;index&nbsp;FK42FCD2D4A5&nbsp;(a_id),&nbsp;add&nbsp;constraint&nbsp;FK42FCD2D4A5&nbsp;foreign&nbsp;key&nbsp;(a_id)&nbsp;references&nbsp;A&nbsp;(id)&nbsp;&nbsp;</span> </li></ol></div><pre style="display: none" class="java" name="code">create table A (id integer not null auto_increment, aname varchar(255), i_id integer, primary key (id))
create table B (id integer not null auto_increment, bname varchar(255), a_id integer, primary key (id))
alter table A add index FK41FCD6779E (i_id), add constraint FK41FCD6779E foreign key (i_id) references B (id)
alter table B add index FK42FCD2D4A5 (a_id), add constraint FK42FCD2D4A5 foreign key (a_id) references A (id)</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;如果没有写@JoinColumn(name="b")则默认是关联属性名+下划线+id</p>
<p>最终sql：</p>
<p>&nbsp;</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div></div>
<ol class="dp-j"><li><span>create&nbsp;table&nbsp;A&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;aname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;b_id&nbsp;integer,&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></li><li><span>create&nbsp;table&nbsp;B&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;bname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></span></li><li><span>alter&nbsp;table&nbsp;A&nbsp;add&nbsp;index&nbsp;FK41FCD34905&nbsp;(b_id),&nbsp;add&nbsp;constraint&nbsp;FK41FCD34905&nbsp;foreign&nbsp;key&nbsp;(b_id)&nbsp;references&nbsp;B&nbsp;(id)&nbsp;&nbsp;</span> </li></ol></div><pre style="display: none" class="java" name="code">create table A (id integer not null auto_increment, aname varchar(255), b_id integer, primary key (id))
create table B (id integer not null auto_increment, bname varchar(255), primary key (id))
alter table A add index FK41FCD34905 (b_id), add constraint FK41FCD34905 foreign key (b_id) references B (id)</pre>
<p>&nbsp;可以使用@JoinColumn(referencedColumnName="bname")让主关联方不关联被关联放的主键</p>
<p>最终sql</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <img alt="复制代码" src="http://coffeef.javaeye.com/images/icon_copy.gif" /></div></div>
<ol class="dp-j"><li><span>create&nbsp;table&nbsp;A&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;aname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;b_bname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></li><li><span>create&nbsp;table&nbsp;B&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;bname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;primary&nbsp;key&nbsp;(id),&nbsp;unique&nbsp;(bname)) &nbsp;&nbsp;</span></span></li><li><span>alter&nbsp;table&nbsp;A&nbsp;add&nbsp;index&nbsp;FK41E47CD6BD&nbsp;(b_bname),&nbsp;add&nbsp;constraint&nbsp;FK41E47CD6BD&nbsp;foreign&nbsp;key&nbsp;(b_bname)&nbsp;references&nbsp;B&nbsp;(bname)&nbsp;&nbsp;</span> </li></ol></div><pre style="display: none" class="java" name="code">create table A (id integer not null auto_increment, aname varchar(255), b_bname varchar(255), primary key (id))
create table B (id integer not null auto_increment, bname varchar(255), primary key (id), unique (bname))
alter table A add index FK41E47CD6BD (b_bname), add constraint FK41E47CD6BD foreign key (b_bname) references B (bname)</pre>
<p>&nbsp;&nbsp;3 关联表</p>
<p>&nbsp;使用</p>
<p>@OneToOne(cascade=CascadeType.ALL)<br />&nbsp;@JoinTable(name="centert",joinColumns=@JoinColumn(name="aid"),inverseJoinColumns=@JoinColumn(name="bid"))</p>
<p>最终sql：</p>
<div class="quote_title">写道</div>
<div class="quote_div">create table A (id integer not null auto_increment, aname varchar(255), primary key (id)) <br />create table B (id integer not null auto_increment, bname varchar(255), primary key (id)) <br />create table centert (bid integer, aid integer not null, primary key (aid)) <br />alter table centert add index FK27A6BEBFFCA6C7EA (bid), add constraint FK27A6BEBFFCA6C7EA foreign key (bid) references B (id) <br />alter table centert add index FK27A6BEBFFCA6C428 (aid), add constraint FK27A6BEBFFCA6C428 foreign key (aid) references A (id) <br /></div>
<p>&nbsp;</p>
<p>manytoone</p>
<p>和onetoone很相似</p>
<p>特殊情况：果不写：mappedBy这会产生中间表：</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div></div>
<ol class="dp-j"><li><span>create&nbsp;table&nbsp;A&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;aname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;i_id&nbsp;integer,&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></li><li><span>create&nbsp;table&nbsp;B&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;bname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></span></li><li><span>create&nbsp;table&nbsp;B_A&nbsp;(B_id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>,&nbsp;a_id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>,&nbsp;unique&nbsp;(a_id)) &nbsp;&nbsp;</span></span></li><li><span>alter&nbsp;table&nbsp;A&nbsp;add&nbsp;index&nbsp;FK41FCD6779E&nbsp;(i_id),&nbsp;add&nbsp;constraint&nbsp;FK41FCD6779E&nbsp;foreign&nbsp;key&nbsp;(i_id)&nbsp;references&nbsp;B&nbsp;(id) &nbsp;&nbsp;</span></li><li><span>alter&nbsp;table&nbsp;B_A&nbsp;add&nbsp;index&nbsp;FK10384FCD34905&nbsp;(B_id),&nbsp;add&nbsp;constraint&nbsp;FK10384FCD34905&nbsp;foreign&nbsp;key&nbsp;(B_id)&nbsp;references&nbsp;B&nbsp;(id) &nbsp;&nbsp;</span></li><li><span>alter&nbsp;table&nbsp;B_A&nbsp;add&nbsp;index&nbsp;FK10384FCD2D4A5&nbsp;(a_id),&nbsp;add&nbsp;constraint&nbsp;FK10384FCD2D4A5&nbsp;foreign&nbsp;key&nbsp;(a_id)&nbsp;references&nbsp;A&nbsp;(id)&nbsp;&nbsp;</span> </li></ol></div><pre style="display: none" class="java" name="code">create table A (id integer not null auto_increment, aname varchar(255), i_id integer, primary key (id))
create table B (id integer not null auto_increment, bname varchar(255), primary key (id))
create table B_A (B_id integer not null, a_id integer not null, unique (a_id))
alter table A add index FK41FCD6779E (i_id), add constraint FK41FCD6779E foreign key (i_id) references B (id)
alter table B_A add index FK10384FCD34905 (B_id), add constraint FK10384FCD34905 foreign key (B_id) references B (id)
alter table B_A add index FK10384FCD2D4A5 (a_id), add constraint FK10384FCD2D4A5 foreign key (a_id) references A (id)</pre>
<p>&nbsp;</p>
<p>&nbsp;如</p>
<p>targetEntity属性可以关联接口</p>
<p>例如接口代码 </p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div></div>
<ol class="dp-j"><li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">interface</span><span>&nbsp;I&nbsp;{ &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span> </li></ol></div><pre style="display: none" class="java" name="code">public interface I {
}</pre>
<p>&nbsp;class B implments I</p>
<p>关联方：</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div></div>
<ol class="dp-j"><li><span class="keyword">private</span><span>&nbsp;I&nbsp;i; &nbsp;&nbsp;</span></li><li><span class="annotation">@ManyToOne</span><span>(targetEntity=B.</span><span class="keyword">class</span><span>) &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;I&nbsp;getI()&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;i; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;</span> </li></ol></div><pre style="display: none" class="java" name="code">private I i;
@ManyToOne(targetEntity=B.class)
public I getI() {
return i;
}</pre>
<p>&nbsp;</p>
<p>最终sql：</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 </div></div>
<ol class="dp-j"><li><span>create&nbsp;table&nbsp;A&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;aname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;i_id&nbsp;integer,&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></li><li><span>create&nbsp;table&nbsp;B&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;bname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></span></li><li><span>alter&nbsp;table&nbsp;A&nbsp;add&nbsp;index&nbsp;FK41FCD6779E&nbsp;(i_id),&nbsp;add&nbsp;constraint&nbsp;FK41FCD6779E&nbsp;foreign&nbsp;key&nbsp;(i_id)&nbsp;references&nbsp;B&nbsp;(id)&nbsp;&nbsp;</span> </li></ol></div><pre style="display: none" class="java" name="code">create table A (id integer not null auto_increment, aname varchar(255), i_id integer, primary key (id))
create table B (id integer not null auto_increment, bname varchar(255), primary key (id))
alter table A add index FK41FCD6779E (i_id), add constraint FK41FCD6779E foreign key (i_id) references B (id)</pre>
<p>&nbsp;</p></div><img src ="http://www.blogjava.net/freeman1984/aggbug/300700.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2009-11-02 14:54 <a href="http://www.blogjava.net/freeman1984/archive/2009/11/02/300700.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate annoation (七 继承映射)</title><link>http://www.blogjava.net/freeman1984/archive/2009/11/02/300702.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 02 Nov 2009 06:54:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2009/11/02/300702.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/300702.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2009/11/02/300702.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/300702.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/300702.html</trackback:ping><description><![CDATA[<div class="blog_content">
<p>Table per Class Strategy: the &lt;union-class&gt; element in Hibernate <br />
Single Table per Class Hierarchy Strategy: the &lt;subclass&gt; element in Hibernate <br />
Joined Subclass Strategy: the &lt;joined-subclass&gt; element in Hibernate <br />
ejb支持三种映射关系<br />
1，每个类一张表 （hibertnate里对应&lt;union-class&gt;）<br />
2，每个类层次一张表 (在 hibernate里对应&lt;subclass&gt;)<br />
3，连接的子类(对应join-subclass)</p>
<p>&nbsp;&nbsp; 目前不支持在接口上进行注解<br />
（1）每个类一张表:<br />
在父类class-level上设置：@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)<br />
例如：</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <img alt="复制代码" src="http://coffeef.javaeye.com/images/icon_copy.gif" /></div>
</div>
<ol class="dp-j">
    <li><span><span class="keyword">class</span><span>&nbsp;A代码： &nbsp;&nbsp;</span></span></li>
    <li><span class="annotation">@Entity</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="annotation">@Inheritance</span><span>(strategy=InheritanceType.TABLE_PER_CLASS) &nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;A&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;</span><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;id; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;aname; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;</span><span class="annotation">@Id</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;</span><span class="annotation">@GeneratedValue</span><span>(strategy=GenerationType.IDENTITY) &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">int</span><span>&nbsp;getId()&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;id; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;setId(</span><span class="keyword">int</span><span>&nbsp;id)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span><span class="keyword">this</span><span>.id&nbsp;=&nbsp;id; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;</span><span class="keyword">public</span><span>&nbsp;String&nbsp;getAname()&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;aname; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;setAname(String&nbsp;aname)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span><span class="keyword">this</span><span>.aname&nbsp;=&nbsp;aname; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span class="keyword">class</span><span>&nbsp;B&nbsp;</span><span class="keyword">extends</span><span>&nbsp;A代码： &nbsp;&nbsp;</span></span></li>
    <li><span class="annotation">@Entity</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;B&nbsp;</span><span class="keyword">extends</span><span>&nbsp;A{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;bname; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;</span><span class="keyword">public</span><span>&nbsp;String&nbsp;getBname()&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;bname; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;setBname(String&nbsp;bname)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span><span class="keyword">this</span><span>.bname&nbsp;=&nbsp;bname; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>} &nbsp;&nbsp;</span></li>
    <li><span class="keyword">class</span><span>&nbsp;C&nbsp;</span><span class="keyword">extends</span><span>&nbsp;A代码： &nbsp;&nbsp;</span></span></li>
    <li><span class="annotation">@Entity</span><span>&nbsp;&nbsp;</span></span></li>
    <li><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;C&nbsp;</span><span class="keyword">extends</span><span>&nbsp;A{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;cname; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;</span><span class="keyword">public</span><span>&nbsp;String&nbsp;getCname()&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;cname; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;setCname(String&nbsp;cname)&nbsp;{ &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;</span><span class="keyword">this</span><span>.cname&nbsp;=&nbsp;cname; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;} &nbsp;&nbsp;</span></li>
    <li><span>&nbsp;&nbsp;</span></li>
    <li><span>&nbsp; &nbsp;&nbsp;</span></li>
    <li><span>}&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">class A代码：
@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class A {
private int id;
private String aname;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getAname() {
return aname;
}
public void setAname(String aname) {
this.aname = aname;
}
}
class B extends A代码：
@Entity
public class B extends A{
private String bname;
public String getBname() {
return bname;
}
public void setBname(String bname) {
this.bname = bname;
}
}
class C extends A代码：
@Entity
public class C extends A{
private String cname;
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
}
</pre>
<p>&nbsp;</p>
<p>最终生成sql语句：</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <img alt="复制代码" src="http://coffeef.javaeye.com/images/icon_copy.gif" /></div>
</div>
<ol class="dp-j">
    <li><span><span>create&nbsp;table&nbsp;A&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;aname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></span></li>
    <li><span>create&nbsp;table&nbsp;B&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>,&nbsp;aname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;bname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></span></li>
    <li><span>create&nbsp;table&nbsp;C&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>,&nbsp;aname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;cname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;primary&nbsp;key&nbsp;(id))&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">create table A (id integer not null auto_increment, aname varchar(255), primary key (id))
create table B (id integer not null, aname varchar(255), bname varchar(255), primary key (id))
create table C (id integer not null, aname varchar(255), cname varchar(255), primary key (id))
</pre>
<p>&nbsp;</p>
<p>B 和 C 都继承了A但是没有关联</p>
<p>（2）每个类层次一张表：也就是所有继承的类和父类共享一张表 通过一个辨别符号进行区分<br />
这需要在父类上使用：@Inheritance(strategy=InheritanceType.SINGLE_TABLE)<br />
这样的话在表里面会多出一个字段：DTYPE（默认 默认值为entry.class） <br />
可以通过在父类class-level上设置<br />
@DiscriminatorColumn(name="mytype",discriminatorType=DiscriminatorType.STRING)<br />
在之类上使用<br />
例如：<br />
@Entity<br />
@DiscriminatorValue(value="ctype")<br />
插入数据时候将会有下列语句产生：Hibernate: insert into A (aname, cname, mytype) values (?, ?, 'ctype')；</p>
<p>（3）每个字类一张表：也就是字类的关联到父类的主键<br />
&nbsp;通过在父类上使用：@Inheritance(strategy=InheritanceType.JOINED)<br />
&nbsp;产生语句：默认id关联</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <img alt="复制代码" src="http://coffeef.javaeye.com/images/icon_copy.gif" /></div>
</div>
<ol class="dp-j">
    <li><span><span>create&nbsp;table&nbsp;A&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;aname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></span></li>
    <li><span>create&nbsp;table&nbsp;B&nbsp;(bname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>,&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></span></li>
    <li><span>create&nbsp;table&nbsp;C&nbsp;(cname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>,&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></span></li>
    <li><span>alter&nbsp;table&nbsp;B&nbsp;add&nbsp;index&nbsp;FK42FCA55807&nbsp;(id),&nbsp;add&nbsp;constraint&nbsp;FK42FCA55807&nbsp;foreign&nbsp;key&nbsp;(id)&nbsp;references&nbsp;A&nbsp;(id) &nbsp;&nbsp;</span></li>
    <li><span>alter&nbsp;table&nbsp;C&nbsp;add&nbsp;index&nbsp;FK43FCA55807&nbsp;(id),&nbsp;add&nbsp;constraint&nbsp;FK43FCA55807&nbsp;foreign&nbsp;key&nbsp;(id)&nbsp;references&nbsp;A&nbsp;(id)&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code"> create table A (id integer not null auto_increment, aname varchar(255), primary key (id))
create table B (bname varchar(255), id integer not null, primary key (id))
create table C (cname varchar(255), id integer not null, primary key (id))
alter table B add index FK42FCA55807 (id), add constraint FK42FCA55807 foreign key (id) references A (id)
alter table C add index FK43FCA55807 (id), add constraint FK43FCA55807 foreign key (id) references A (id)</pre>
<p>&nbsp;<br />
也可以指定关联 例如：在B的class-level上使用@PrimaryKeyJoinColumn(name="bid")<br />
生成sql语句：</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <img alt="复制代码" src="http://coffeef.javaeye.com/images/icon_copy.gif" /></div>
</div>
<ol class="dp-j">
    <li><span><span>create&nbsp;table&nbsp;B&nbsp;(bname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;bid&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>,&nbsp;primary&nbsp;key&nbsp;(bid)) &nbsp;&nbsp;</span></span></li>
    <li><span>alter&nbsp;table&nbsp;B&nbsp;add&nbsp;index&nbsp;FK42FCA6C7E9&nbsp;(bid),&nbsp;add&nbsp;constraint&nbsp;FK42FCA6C7E9&nbsp;foreign&nbsp;key&nbsp;(bid)&nbsp;references&nbsp;A&nbsp;(id)&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">create table B (bname varchar(255), bid integer not null, primary key (bid))
alter table B add index FK42FCA6C7E9 (bid), add constraint FK42FCA6C7E9 foreign key (bid) references A (id)</pre>
<p>&nbsp;<br />
但是我们不能关联到A的非主键字段例如：<br />
在B上使用<br />
@PrimaryKeyJoinColumn(name="bid",referencedColumnName="aname")则会报错：SecondaryTable JoinColumn cannot reference a non primary key<br />
&nbsp; 当然也可以给之类关联设置不同的类型例如：@PrimaryKeyJoinColumn(name="bid",columnDefinition="carchar(20)")但是不能设置不能转换的类型例如：<br />
@PrimaryKeyJoinColumn(name="bid",columnDefinition="blob")则会建立不了关联</p>
<p>（4）从实体继承 但是父类不持久化：使用@MappedSuperclass<br />
sql语句：</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <img alt="复制代码" src="http://coffeef.javaeye.com/images/icon_copy.gif" /></div>
</div>
<ol class="dp-j">
    <li><span><span>create&nbsp;table&nbsp;B&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;aname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;bname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;primary&nbsp;key&nbsp;(id)) &nbsp;&nbsp;</span></span></li>
    <li><span>create&nbsp;table&nbsp;C&nbsp;(id&nbsp;integer&nbsp;not&nbsp;</span><span class="keyword">null</span><span>&nbsp;auto_increment,&nbsp;aname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;cname&nbsp;varchar(</span><span class="number">255</span><span>),&nbsp;primary&nbsp;key&nbsp;(id))&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">create table B (id integer not null auto_increment, aname varchar(255), bname varchar(255), primary key (id))
create table C (id integer not null auto_increment, aname varchar(255), cname varchar(255), primary key (id))</pre>
<p>&nbsp;<br />
&nbsp;当然可以使用@AttributeOverride或者@AssociationOverride进行覆盖</p>
</div>
 <img src ="http://www.blogjava.net/freeman1984/aggbug/300702.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2009-11-02 14:54 <a href="http://www.blogjava.net/freeman1984/archive/2009/11/02/300702.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>spring hibernate 二级缓存</title><link>http://www.blogjava.net/freeman1984/archive/2009/11/02/300696.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 02 Nov 2009 06:43:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2009/11/02/300696.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/300696.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2009/11/02/300696.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/300696.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/300696.html</trackback:ping><description><![CDATA[<p>步骤：</p>
<p>1：配置：</p>
<p>&nbsp;</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://coffeef.javaeye.com/admin/blogs/469001#"><img alt="复制代码" src="http://coffeef.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>&lt;prop&nbsp;key=</span><span class="string">"hibernate.cache.provider_class"</span><span>&gt;org.hibernate.cache.EhCacheProvider&lt;/prop&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;prop&nbsp;key=</span><span class="string">"hibernate.cache.use_query_cache"</span><span>&gt;</span><span class="keyword">true</span><span>&lt;/prop&gt;&nbsp;&nbsp;</span></span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">&lt;prop key="hibernate.cache.provider_class"&gt;org.hibernate.cache.EhCacheProvider&lt;/prop&gt;
&lt;prop key="hibernate.cache.use_query_cache"&gt;true&lt;/prop&gt;</pre>
<p>&nbsp;2：bean配置：</p>
<div class="quote_title">写道</div>
<div class="quote_div">@Entity <br />
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)</div>
<p>&nbsp;</p>
<p>关于缓存策略介绍可见我的hibernate文章里面的相关内容</p>
<p>3，查询</p>
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" onclick="dp.sh.Toolbar.CopyToClipboard(this);return false;" href="http://coffeef.javaeye.com/admin/blogs/469001#"><img alt="复制代码" src="http://coffeef.javaeye.com/images/icon_copy.gif" /></a></div>
</div>
<ol class="dp-j">
    <li><span><span>HibernateTemplate&nbsp;template&nbsp;=&nbsp;getHibernateTemplate(); &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;SPAN&nbsp;style=</span><span class="string">"COLOR:&nbsp;#ff0000"</span><span>&gt;template.setCacheQueries(</span><span class="keyword">true</span><span>);&lt;/SPAN&gt; &nbsp;&nbsp;</span></span></li>
    <li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;List&nbsp;list&nbsp;=&nbsp;&nbsp;template.loadAll(clazz);&nbsp;&nbsp;</span></li>
</ol>
</div>
<pre class="java" style="display: none" name="code">HibernateTemplate template = getHibernateTemplate();
<span style="color: #ff0000">template.setCacheQueries(true);</span>
List list =  template.loadAll(clazz);</pre>
<p>&nbsp;二级缓存需要和查询缓存配合使用 查询缓存缓存数据的id 并通过id去二级缓存查找</p>
 <img src ="http://www.blogjava.net/freeman1984/aggbug/300696.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2009-11-02 14:43 <a href="http://www.blogjava.net/freeman1984/archive/2009/11/02/300696.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate spring 事务</title><link>http://www.blogjava.net/freeman1984/archive/2009/08/31/293867.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 31 Aug 2009 08:39:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2009/08/31/293867.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/293867.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2009/08/31/293867.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/293867.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/293867.html</trackback:ping><description><![CDATA[<p>&nbsp;</p>
<p>在我们的项目中我们可以使用spring的事务机制来处理，以此来节省工作量，一下就例子来讨论下：</p>
<p>实例：</p>
<p><span style="color: #ff0000">采用spring2.x版本：hibenate3.x</span></p>
<p>首先：</p>
<p>看sessionfactory的配置，我们使用hibenate的sessionfactory配置：</p>
<p>&lt;?xml version="1.0" encoding="UTF-8"?&gt; &lt;beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd" default-autowire="byName" default-lazy-init="true"&gt; &lt;bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"&gt;<span style="color: #ff0000">----//在此由于我使用的是annoation形式的po 如果配置其他将不能持久化</span> &lt;property name="configLocation" value="classpath:hibernate.cfg.xml"&gt;&lt;/property&gt; &lt;/bean&gt;&gt;&lt;/beans&gt;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;</p>
<p>&nbsp;当然也可以使用spring的datasource来配置，也就是使用：<span style="color: #ff0000"><strong>org.springframework.jdbc.datasource.DriverManagerDataSource</strong></span>,自我感觉这样分开比较好</p>
<p>&nbsp;hibernate.cfg.xml:</p>
<p>&lt;?xml version='1.0' encoding='UTF-8'?&gt; &lt;!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"&gt; &lt;!-- Generated by MyEclipse Hibernate Tools. --&gt; &lt;hibernate-configuration&gt; &lt;session-factory&gt; &lt;property name="connection.url"&gt; jdbc:mysql://localhost:3306/hbman &lt;/property&gt; &lt;property name="connection.username"&gt;root&lt;/property&gt; &lt;property name="connection.password"&gt;root&lt;/property&gt; &lt;property name="connection.driver_class"&gt; com.mysql.jdbc.Driver &lt;/property&gt; &lt;property name="dialect"&gt; org.hibernate.dialect.MySQLDialect &lt;/property&gt; &lt;property name="hibernate.show_sql"&gt;true&lt;/property&gt; &lt;property name="hbm2ddl.auto"&gt;update&lt;/property&gt; &lt;property name="cache.provider_class"&gt; org.hibernate.cache.EhCacheProvider &lt;/property&gt; &lt;property name="cache.use_second_level_cache"&gt;false&lt;/property&gt; &lt;property name="cache.use_query_cache"&gt;false&lt;/property&gt; &lt;property name="connection.isolation"&gt;2&lt;/property&gt; &lt;mapping class="com.po.A" /&gt; &lt;/session-factory&gt; &lt;/hibernate-configuration&gt;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;我们的po类class A(使用hibenate anoation)</p>
<p>&nbsp;</p>
<p>package com.po; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Version; @Entity public class A { private int id; private int anum; private String aname; private int version; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) public int getId() { return id; } public void setId(int id) { this.id = id; } @Version public int getVersion() { return version; } public void setVersion(int version) { this.version = version; } ....get set.. } </p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;</p>
<p>&nbsp;dao：</p>
<p>&nbsp;</p>
<p>public class Dao extends HibernateDaoSupport { public Serializable save(Object entity){ return getHibernateTemplate().save(entity); } } </p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;</p>
<p>测试server：我们在两个需要事物处理的调用之间抛出异常：</p>
<p>public class TestSH { private Dao dao; public void save() throws MyE{ A a = new A(); a.setAname("aname"); a.setAnum(1); dao.save(a); if(true){ throw new MyE("************异常*************"); } A a1 = new A(); a1.setAname("aname1"); a1.setAnum(1); dao.save(a1); }..get set...</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;</p>
<p>&nbsp;<span style="color: #ff0000"><strong>在这说明需要抛出RuntimeException（或者子类）或者Exception的子类，如果抛出Exception将spring将不能对他进行自动回滚，需要我们在文件中配置，如下：</strong></span></p>
<p>&lt;tx:.... rollback-for="java.lang.Exception"/&gt;//<span style="color: #ff0000"><strong>也就是spring所谓的 Winning rollback rule</strong></span></p>
<p><strong><span style="color: #808080">事务配置：</span></strong></p>
<p>&lt;tx:advice id="txAdviceService" transaction-manager="transactionManager"&gt; &lt;tx:attributes&gt; &lt;tx:method name="get*" read-only="true"/&gt; &lt;tx:method name="load*" read-only="true"/&gt; &lt;tx:method name="find*" read-only="true"/&gt; &lt;tx:method name="list*" read-only="true"/&gt; &lt;tx:method name="check*" read-only="true"/&gt; &lt;tx:method name="browse*" read-only="true"/&gt; &lt;tx:method name="search*" read-only="true"/&gt; &lt;tx:method name="*" read-only="false" rollback-for="java.lang.Exception"/&gt; &lt;/tx:attributes&gt; &lt;/tx:advice&gt; &lt;aop:config&gt; &lt;aop:pointcut id="actionMethods" expression="execution(* com.action.*.*(..))"/&gt; &lt;aop:advisor advice-ref="txAdviceService" pointcut-ref="actionMethods"/&gt; &lt;/aop:config&gt; &lt;bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"&gt; &lt;property name="sessionFactory" ref="sessionFactory"/&gt; &lt;/bean&gt;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;测试配置如下：</p>
<p>&lt;bean id="dao" class="com.server.Dao"&gt; &lt;property name="sessionFactory" ref="sessionFactory"&gt;&lt;/property&gt; &lt;/bean&gt; &lt;bean id="test" class="com.action.TestSH"&gt; &lt;property name="dao" ref="dao"&gt;&lt;/property&gt; &lt;/bean&gt;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;</p>
<p><span style="color: #ff0000">
<p><strong>&nbsp;说明：&nbsp;需要自动事务的类必须是spring可加载的也就是需要在文件中配，否则就会出现事务不起作用的情况 具体的讨论文章可见javaeye上</strong></p>
</span>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;测试类：</p>
<p>public class Test { private static TestSH testsh; static{ System.out.println("init....."); ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"applicationContext-*.xml","applicationContext.xml"}); testsh = (TestSH) ctx.getBean("test"); } public static void main(String[] args) { try { testsh.save(); } catch (MyE e) { // TODO Auto-generated catch block e.printStackTrace(); } } } </p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;</p>
<p>&nbsp;最终控制台信息：</p>
<p>09-08-31 16:52:06,187 DEBUG (org.springframework.transaction.interceptor.TransactionInterceptor:282) - <span style="color: #ff0000"><strong>Getting transaction for [com.action.TestSH.save]</strong></span> 2009-08-31 16:52:06,187 DEBUG (org.springframework.transaction.support.TransactionSynchronizationManager:140) - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@191e4c] for key [org.hibernate.impl.SessionFactoryImpl@11415c8] bound to thread [main] 2009-08-31 16:52:06,187 DEBUG (org.springframework.transaction.support.TransactionSynchronizationManager:140) - Retrieved value [org.springframework.orm.hibernate3.SessionHolder@191e4c] for key [org.hibernate.impl.SessionFactoryImpl@11415c8] bound to thread [main] 2009-08-31 16:52:06,187 DEBUG (org.springframework.orm.hibernate3.HibernateTemplate:364) - Found thread-bound Session for HibernateTemplate Hibernate: insert into A (aname, anum, version) values (?, ?, ?) 2009-08-31 16:52:06,234 DEBUG (org.springframework.orm.hibernate3.HibernateTemplate:388) - Not closing pre-bound Hibernate Session after HibernateTemplate 2009-08-31 16:52:16,234 DEBUG (org.springframework.transaction.interceptor.TransactionInterceptor:327) - Completing transaction for [com.action.TestSH.save] after exception: com.exc.MyE: ************异常************* 2009-08-31 16:52:16,234 DEBUG (org.springframework.transaction.interceptor.RuleBasedTransactionAttribute:130) - Applying rules to determine whether transaction should rollback on com.exc.MyE: ************异常************* 2009-08-31 16:52:16,234 DEBUG (org.springframework.transaction.interceptor.RuleBasedTransactionAttribute:148) - Winning rollback rule is: RollbackRuleAttribute with pattern [java.lang.Exception] 2009-08-31 16:52:16,234 DEBUG (org.springframework.orm.hibernate3.HibernateTransactionManager:846) - Triggering beforeCompletion synchronization 2009-08-31 16:52:16,234 DEBUG (org.springframework.orm.hibernate3.HibernateTransactionManager:751) - <span style="color: #ff0000"><strong>Initiating transaction rollback</strong></span> 2009-08-31 16:52:16,234 DEBUG (org.springframework.orm.hibernate3.HibernateTransactionManager:593) - <span style="color: #ff0000"><strong>Rolling back Hibernate transaction on Session [org.hibernate</strong></span>.impl.SessionImpl@4298e] 2009-08-31 16:52:16,265 DEBUG (org.springframework.orm.hibernate3.HibernateTransactionManager:875) - Triggering afterCompletion synchronization 2009-08-31 16:52:16,265 DEBUG (org.springframework.transaction.support.TransactionSynchronizationManager:276) - Clearing transaction synchronization 2009-08-31 16:52:16,265 DEBUG (org.springframework.transaction.support.TransactionSynchronizationManager:193) - Removed value [org.springframework.orm.hibernate3.SessionHolder@191e4c] for key [org.hibernate.impl.SessionFactoryImpl@11415c8] from thread [main] 2009-08-31 16:52:16,265 DEBUG (org.springframework.orm.hibernate3.HibernateTransactionManager:653) - Closing Hibernate Session [org.hibernate.impl.SessionImpl@4298e] after transaction 2009-08-31 16:52:16,265 DEBUG (org.springframework.orm.hibernate3.SessionFactoryUtils:771) - Closing Hibernate Session com.exc.MyE: ************异常************* at com.action.TestSH.save(TestSH.java:29) </p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<pre></pre>
<p>&nbsp;</p>
<p>&nbsp;另外针对事务配置可以在最外层的业务层设置，防止嵌套获取事务的情况（当然不会出现实务问题）。</p>
<p><a href="http://www.javaeye.com/topic/17368?page=4"></a>&nbsp;</p>
<br />
<br />
 <img src ="http://www.blogjava.net/freeman1984/aggbug/293867.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2009-08-31 16:39 <a href="http://www.blogjava.net/freeman1984/archive/2009/08/31/293867.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate 事务 annoation</title><link>http://www.blogjava.net/freeman1984/archive/2009/08/31/293868.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 31 Aug 2009 02:12:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2009/08/31/293868.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/293868.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2009/08/31/293868.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/293868.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/293868.html</trackback:ping><description><![CDATA[<p><span lang="EN-US"><span style="font-family: Verdana">
<p style="line-height: 12pt"><span>事务隔离</span><span lang="EN-US"><br />
<br />
<span>&nbsp; </span></span><span>使用封锁技术，事务对申请的资源加锁，但是会影响数据库性能。根据数据对象封锁的程度，可以分成多种不同的事务隔离级别。</span><span lang="EN-US"><br />
<span>&nbsp; </span></span><span>数据并发执行时，产生不一致的现象：</span><span lang="EN-US"><br />
<span>1</span></span><span>，丢失更新（<span lang="EN-US">Lost Update</span>）</span><span lang="EN-US"><br />
<span>&nbsp; </span></span><span>两个事务读入同一数据并修改，然后提交修改，<span lang="EN-US">T2 </span>提交的结果破坏了<span lang="EN-US"> T1 </span>提交的结果，导致<span lang="EN-US"> T1 </span>的修改丢失。</span><span lang="EN-US"><br />
<span>2</span></span><span>， 不可重复读</span><span lang="EN-US"><br />
<span>&nbsp; </span></span><span>事务<span lang="EN-US">T1 </span>读取数据后，事务<span lang="EN-US">T2 </span>执行了同一数据的跟新操作，使得事务<span lang="EN-US"> T1 </span>无法再现前一次读取的结果。</span><span lang="EN-US"><br />
<span>&nbsp;&nbsp;&nbsp; </span></span><span>事务<span lang="EN-US">1 </span>读取某一数据后，事务<span lang="EN-US">2 </span>对该数据作了修改，事务<span lang="EN-US">1 </span>再次读取时，得到数据和前一次不一致。</span><span lang="EN-US"><br />
<span>&nbsp;&nbsp;&nbsp; ① </span></span><span>事务<span lang="EN-US">1 </span>读取某一些记录后，事务<span lang="EN-US">2 </span>删除了同一数据源的部分数据，事务<span lang="EN-US">1 </span>再次读取时，发现某些记录丢失。</span><span lang="EN-US"><br />
<span>&nbsp;&nbsp;&nbsp; ① </span></span><span>事务<span lang="EN-US">1 </span>读取某一些记录后，事务<span lang="EN-US">2 </span>插入了同一数据源的新数据，事务<span lang="EN-US">1 </span>再次读取时，发现某些记录增加。</span><span lang="EN-US"><br />
<span>3</span></span><span>， 读<span lang="EN-US">&#8220;</span>脏<span lang="EN-US">&#8221;</span>数据</span><span lang="EN-US"><br />
<span>&nbsp; </span></span><span>事务<span lang="EN-US">T1 </span>修改某一数据，并将其写回物理数据库。事务<span lang="EN-US">T2 </span>读取同一数据后，事务<span lang="EN-US">T1 </span>由于某种原因被撤销，数据库将已经修改的数据恢复原值，导致事务<span lang="EN-US">T2 </span>保持的数据和数据库中的数据产生了不一致。</span><span lang="EN-US"><br />
<br />
<span>&nbsp; ANSI SQL-99 </span></span><span>标准定义了下列隔离级别：</span><span lang="EN-US"><br />
<span>Hibernate </span></span><span>在配置文件中声明事务的隔离级别，<span lang="EN-US">Hibenate </span>获取数据库连接后，将根据隔离级别自动设置数据库连接为指定的事务隔离级别。</span><span lang="EN-US"><br />
<span>&lt;property name="connection.isolation"&gt;8&lt;/property&gt;<br />
● </span></span><span>未提交读（<span lang="EN-US">Read Uncommitted</span>）：隔离事务的最低级别，只能保证不会读取到物理上损坏的数据。<span lang="EN-US">Hibernate</span>配置<span lang="EN-US">:1</span>；允许产生：<span lang="EN-US">1</span>，<span lang="EN-US">2</span>，</span><span><span style="font-size: x-small"><span lang="EN-US">3<br />
<br />
● </span>已提交读（<span lang="EN-US">Read Committed</span>）：常见数据库引擎的默认级别，保证一个事务不会读取到另一个事务已修改但未提交的数据。<span lang="EN-US">Hibernate</span>配置<span lang="EN-US">:2</span>；允许产生：<span lang="EN-US">1</span>，</span></span><span><span style="font-size: x-small"><span lang="EN-US">2<br />
<br />
● </span>可重复读（<span lang="EN-US">Repeatable Read</span>）：保证一个事务不能更新已经由另一个事务读取但是未提交的数据。相当于应用中的已提交读和乐观并发控制。<span lang="EN-US">Hibernate</span>配置<span lang="EN-US">:4</span>；允许产生：</span></span><span><span style="font-size: x-small"><span lang="EN-US">1<br />
<br />
● </span>可串行化（<span lang="EN-US">Serializable</span>）：隔离事务的最高级别，事务之间完全隔离。系统开销最大。<span lang="EN-US">Hibernate</span>配置<span lang="EN-US">:8</span>；这种情况很容易造成死锁的问题，<span lang="EN-US">hibernate</span>表现为：</span></span></p>
<pre><span lang="EN-US"><span style="font-size: x-small">Deadlock found when trying to get lock; try restarting transaction</span></span><span lang="EN-US">
<span>2-3</span></span><span>、并发控制类型</span><span lang="EN-US">
<span>&nbsp; </span></span><span>根据使用的锁定策略和隔离等级，可以把事务的并发控制分为两种：</span><span lang="EN-US">
<span>① </span></span><span>悲观并发控制</span><span lang="EN-US">
<span>&nbsp;
&nbsp; </span></span><span>用户使用时锁定数据。主要应用于数据争用激烈的环境中，以及发生并发冲突时用锁保护数据的成本低于回滚事务成本的环境中。</span><span lang="EN-US">
<span>&nbsp; Hibernate </span></span><span>的悲观锁定不在内存中锁定数据，由底层数据库负责完成。</span><span lang="EN-US">
<span>② </span></span><span>乐观并发控制</span><span lang="EN-US">
<span>&nbsp;
&nbsp; </span></span><span>用户读取数据时不锁定数据。当一个用户更新数据时，系统将进行检查该用户读取数据后其他用户是否更改了该数据，是则产生一个错误，一般情况下，收到错误信息的用户将回滚事务并重新开始。主要用户数据争用不大，且偶尔回滚事务的成本低于读取数据时锁定数据的成本的环境中。</span><span lang="EN-US">
<span>&nbsp; Hibernate </span></span><span>中使用元素<span lang="EN-US"> version </span>和<span lang="EN-US"> timestamp </span>实现乐观并发控制模式的版本控制，并提供多种编程方式。版本是数据库表中的一个字段，可以是一个递增的整数，也可以是一个时间戳，它们对应<span lang="EN-US"> Java </span>持久化类的一个属性。事务提交成功后，<span lang="EN-US">Hibernate </span>自动修改版本号。如果另外一个事务同时访问同一数据，若发现提交前的版本号和事前载入的版本号有出入，则认为发生了冲突，事务停止执行，撤销操作，并抛出异常。应用程序必须捕捉该异常并做出一定的处理。</span><span lang="EN-US">
<span>⒈</span></span><span>应用程序级别的版本控制</span><span lang="EN-US">
<span>⒉</span></span><span>长生命周期会话的自动化版本控制</span><span lang="EN-US">
<span>⒊</span></span><span>托管对象的自动化版本控制</span><span lang="EN-US">
<span>⒋</span></span><span>定制自动化版本控制</span></pre>
<p style="line-height: 12pt"><span lang="EN-US"><span>&nbsp;</span></span></p>
<p style="line-height: 12pt"><span><span style="font-size: x-small"><span lang="EN-US">&nbsp;</span>二 实际应用中我们使用<span lang="EN-US">Read Committed</span>作为我们的事务级别 也就是 已提交读（<span lang="EN-US">Read Committed</span>），因为如果用户 有权限 修改一个 数据 ，那 那么 就可以提交这个事务，这是系统需要解决的权限问题，由于这种情况会造成第二类数据丢失的情况，因此要配备乐观锁的机制，这种事物方法使用比较多。下面 举例实验：</span></span></p>
<p style="line-height: 12pt"><span><span style="font-size: x-small"><span lang="EN-US">1</span>，例如<span lang="EN-US">A</span>持久化后会被事务关联（事务针对修改，插入，不针对查询，如果对于一般不需要修改的表，如字典表，可以不配置事务，而是配置二级缓存来提高性能）</span></span></p>
<p style="line-height: 12pt"><span><span style="font-size: x-small"><span lang="EN-US">class A</span>代码（先不加乐观锁，会造成第二类数据丢失）：</span></span></p>
<p>&nbsp;</p>
<pre class="java">@Entity
public class A {
private int id;
private int anum;
private String aname;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
public int getId() {
return id;
}
//get..set
}</pre>
<p style="line-height: 12pt">&nbsp;</p>
<p>&nbsp;</p>
<p style="line-height: 12pt"><span><span style="font-size: x-small"><span lang="EN-US">&nbsp;hibernate</span>配置：<span lang="EN-US">&lt;property name="connection.isolation"&gt;2&lt;/property&gt;</span></span></span></p>
<p style="line-height: 12pt"><span>事先插入一条数据（<span lang="EN-US">a.setAnum(1);</span>）</span></p>
<p style="line-height: 12pt"><span>测试代码：</span></p>
<p>&nbsp;</p>
<pre class="java">public static void test(){
new Thread(new Runnable(){//线程2，启动事务后不提交，然后让线程1启动
public void run() {
Session session = HibernateSessionFactory.getSession();
Transaction tt = session.beginTransaction();
System.out.println("t2 statr....");
A a = (A) session.get(A.class, 1);
System.out.println("未修改之前的num："+a.getAnum());
a.setAnum(a.getAnum()+1);
session.update(a);
try {
Thread.sleep(5000);//让出时间让线程1执行
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
tt.commit();
session.clear();//清除一级缓存
System.out.println("t2 cummit end....");
A a1 = (A) session.get(A.class, 1);
System.out.println("修改之后的num："+a1.getAnum());
session.close();
}
}).start();//正确结果为1+1=2
new Thread(new Runnable(){
public void run() {
Session session = HibernateSessionFactory.getSession();
Transaction tt = session.beginTransaction();
System.out.println("t1 statr....");
A a = (A) session.get(A.class, 1);
a.setAnum(a.getAnum()+2);
session.update(a);
tt.commit();
System.out.println("1 cummit end....");
session.clear();//清除一级缓存
session.close();
}
}).start();//正确结果为1+1=3
}</pre>
<p style="line-height: 12pt">&nbsp;</p>
<p>&nbsp;</p>
<p style="line-height: 12pt"><span><span style="font-size: x-small"><span lang="EN-US">&nbsp;</span>打印信息：</span></span></p>
<p>&nbsp;</p>
<pre class="java">t2 statr....
Hibernate: select a0_.id as id0_0_, a0_.aname as aname0_0_, a0_.anum as anum0_0_ from A a0_ where a0_.id=?//让出时间让t1执行
t1 statr....
Hibernate: select a0_.id as id0_0_, a0_.aname as aname0_0_, a0_.anum as anum0_0_ from A a0_ where a0_.id=?
未修改之前的num：1
Hibernate: update A set aname=?, anum=? where id=?
1 cummit end....
Hibernate: update A set aname=?, anum=? where id=?
t2 cummit end....
Hibernate: select a0_.id as id0_0_, a0_.aname as aname0_0_, a0_.anum as anum0_0_ from A a0_ where a0_.id=?
修改之后的num：2</pre>
<p style="line-height: 12pt">&nbsp;</p>
<p>&nbsp;</p>
<p style="line-height: 12pt"><span><span style="font-size: x-small"><span lang="EN-US">&nbsp;</span>可以看出他<span lang="EN-US">t1</span>本来应该是<span lang="EN-US">3</span>但是被<span lang="EN-US">t2</span>覆盖<span lang="EN-US"> </span></span></span></p>
<p style="line-height: 12pt"><span lang="EN-US"><span>&nbsp;</span></span></p>
<p style="line-height: 12pt"><span><span style="font-size: x-small"><span lang="EN-US">&nbsp;</span>为此我们加上锁：</span></span></p>
<p style="line-height: 12pt"><span>修改<span lang="EN-US">A</span>（锁可以有两种，<span lang="EN-US">version</span>，和时间锁，但是时间锁有个精确度问题）使用<span lang="EN-US">version</span>：</span></p>
<p>&nbsp;</p>
<pre class="java">private int version;
...
@Version//使用version注释来表明版本控制
public int getVersion() {
return version;
}</pre>
<p style="line-height: 12pt">&nbsp;</p>
<p>&nbsp;</p>
<p style="line-height: 12pt"><span><span style="font-size: x-small"><span lang="EN-US">&nbsp;</span>测试（同样的测试代码）<span lang="EN-US">:</span></span></span></p>
<p style="line-height: 12pt"><span>打印信息：</span></p>
<p>&nbsp;</p>
<pre class="java">t2 statr....
Hibernate: select a0_.id as id0_0_, a0_.aname as aname0_0_, a0_.anum as anum0_0_, a0_.version as version0_0_ from A a0_ where a0_.id=?
t1 statr....
Hibernate: select a0_.id as id0_0_, a0_.aname as aname0_0_, a0_.anum as anum0_0_, a0_.version as version0_0_ from A a0_ where a0_.id=?
未修改之前的num：1
Hibernate: update A set aname=?, anum=?, version=? where id=? and version=?
1 cummit end....
Hibernate: update A set aname=?, anum=?, version=? where id=? and version=?
Exception in thread "Thread-0" org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [com.eric.po.A#1]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1792)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2435)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2335)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2635)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:115)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
at com.eric.dao.Testcreate$1.run(Testcreate.java:139)
at java.lang.Thread.run(Thread.java:619)</pre>
<p style="line-height: 12pt">&nbsp;</p>
<p>&nbsp;</p>
<p style="line-height: 12pt"><span style="font-size: x-small"><span lang="EN-US">&nbsp;</span>此时乐观所就起作用了，防止了数据的丢失。针对异常可自行捕获。</span></p>
<p style="line-height: 12pt"><span lang="EN-US"><span style="font-size: x-small">&nbsp;</span></span></p>
<p class="MsoNormal" style="margin: 0cm 0cm 0pt; line-height: 12pt"><span lang="EN-US"><span style="font-size: x-small; font-family: Times New Roman">&nbsp;</span></span></p>
<span lang="EN-US"><font size="+0">
<p>&nbsp;</p>
</font></span></span></span>&nbsp;
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<br />
<br />
 <img src ="http://www.blogjava.net/freeman1984/aggbug/293868.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2009-08-31 10:12 <a href="http://www.blogjava.net/freeman1984/archive/2009/08/31/293868.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate  (十一 缓存Ehcache 采用annoation)</title><link>http://www.blogjava.net/freeman1984/archive/2009/08/24/293871.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Mon, 24 Aug 2009 09:09:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2009/08/24/293871.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/293871.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2009/08/24/293871.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/293871.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/293871.html</trackback:ping><description><![CDATA[<p>从hibernate2.1开始ehcache已经作为hibernate的默认缓存方案（二级缓存方案 sessionfactory级别）， 在项目中有针对性的使用缓存将对性能的提升右很大的帮助。<br />
<br />
要使用 Ehcache：需要一下步骤<br />
一，classpath添加相应的jar（ehcache，commons-logging） <br />
<br />
二，然后在hibernate.cfg.xml中配置 <br />
<br />
&lt;property name="cache.provider_class"&gt;org.hibernate.cache.EhCacheProvider&lt;/property&gt;<br />
&nbsp;&lt;property name="cache.use_second_level_cache"&gt;true&lt;/property&gt;<br />
&nbsp;&lt;property name="cache.use_query_cache"&gt;true&lt;/property&gt;</p>
<p>说明：如果没有配置&lt;property name="cache.use_second_level_cache"&gt;true&lt;/property&gt;(默认false) 将会产生根据单个id查询的情况（产生很多sql）。<br />
<br />
三，为需要缓存的类添加缓存标示： <br />
<br />
使用mapping文件时需要添加node ：</p>
<pre class="java">@Entity
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)</pre>
<p>&nbsp;<br />
如果使用使用hibernate annoation是使用@Cache(usage=CacheConcurrencyStrategy.)标签，有5种可选的缓存方案： <br />
<br />
1，CacheConcurrencyStrategy.NONE <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不适用，默认 <br />
<br />
2.&nbsp; CacheConcurrencyStrategy.NONSTRICT_READ_WRITE <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 更新不频繁几个小时或更长 <br />
<br />
3，CacheConcurrencyStrategy.READ_ONLY <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 对于不发生改变的数据使用 <br />
<br />
4，CacheConcurrencyStrategy.READ_WRITE <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 基于时间戳判定机制，，对于数据同步要求严格的情况，使用频繁 <br />
<br />
5，CacheConcurrencyStrategy.TRANSACTIONAL <br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 运行在jta环境种，基于事务<br />
<br />
<br />
四，在classpath下添加ehcache.xml </p>
<p>&nbsp;</p>
<div class="quote_title">写道</div>
<div class="quote_div">＜ehcache＞ <br />
　＜diskStore path="java.io.tmpdir"/＞ <br />
　　＜defaultCache <br />
　　　maxElementsInMemory="10000" ＜!-- 缓存最大数目 --＞ <br />
　　　eternal="false" ＜!-- 缓存是否持久 --＞ <br />
　　　overflowToDisk="true" ＜!-- 是否保存到磁盘，当系统当机时--＞ <br />
　　　timeToIdleSeconds="300" ＜!-- 当缓存闲置n秒后销毁 --＞ <br />
　　　timeToLiveSeconds="180" ＜!-- 当缓存存活n秒后销毁--＞ <br />
　　　diskPersistent="false" <br />
　　　diskExpiryThreadIntervalSeconds= "120"/＞ <br />
＜/ehcache＞ <br />
</div>
<p>&nbsp;</p>
<p>测试：</p>
<pre class="java">@Entity
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY)
public class B {
private int id;
private String bname;
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
public int getId() {
return id;
}
public String getBname() {
return bname;
}
...
}</pre>
<p>&nbsp;并配置到cfg文件中：&lt;mapping class="com.eric.po.B" /&gt;<br />
&nbsp;&nbsp; main方法：</p>
<pre class="java">public static void main(String[] args) throws Exception  {
getTest();
getTest();
}</pre>
<pre class="java">public static void getTest() throws Exception {
&nbsp;&nbsp;Session session = HibernateSessionFactory.getSession();
&nbsp;&nbsp;Query q = session.createQuery("from B where id&gt;?");
&nbsp;&nbsp;q.setParameter(0, 10);
&nbsp;&nbsp;q.setCacheable(true); 需要设置此属性
&nbsp;&nbsp;List list = q.list();
&nbsp;&nbsp;for (Iterator iterator = list.iterator(); iterator.hasNext();) {
&nbsp;&nbsp;&nbsp;B a2 = (B) iterator.next();
&nbsp;&nbsp;&nbsp;System.out.print(a2.getId() + "/");
&nbsp;&nbsp;}
&nbsp;&nbsp;HibernateSessionFactory.closeSession();
&nbsp;}</pre>
<p>&nbsp;控制台信息：</p>
<pre class="java">Hibernate: select b0_.id as id1_, b0_.bname as bname1_ from B b0_ where b0_.id&gt;?
11/14/18/25/26/27/28/29/Hibernate: select b0_.id as id1_, b0_.bname as bname1_ from B b0_ where b0_.id&gt;?
11/14/18/25/26/27/28/29/</pre>
<p>&nbsp;只发出了一次sql 第二次从缓存中取</p>
<p>&nbsp;</p>
<p>&nbsp;我们配置我们自己的缓存文件：</p>
<p>&nbsp;</p>
<pre class="java"> &lt;cache name="cache_a"
maxElementsInMemory="5"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/&gt;</pre>
<p>我们将maxElementsInMemory设置小一点 我们就可以看见磁盘的缓存文件：</p>
<p>&nbsp; </p>
<p>&nbsp;&nbsp; 首先说明：我们在ehcache.xml &nbsp;&lt;diskStore path="java.io.tmpdir"/&gt;配置了缓存溢出到的磁盘路径</p>
<p>可以通过：</p>
<pre class="java">System.out.println(System.getProperty("java.io.tmpdir"));</pre>
<p>&nbsp;查询。</p>
<p>测试代码：</p>
<pre class="java">public static void main(String[] args) throws Exception  {</pre>
<pre class="java">System.out.println(System.getProperty("java.io.tmpdir"));
getTest();
getTest();
Thread.sleep(10000);</pre>
<pre class="java">}</pre>
<p>&nbsp;我们在最后暂停10秒来查看磁盘文件<br />
&nbsp;&nbsp;&nbsp;&nbsp;</p>
<pre class="java">public static void getTest() throws Exception {
Session session = HibernateSessionFactory.getSession();
Query q = session.createQuery("from B where id&gt;?");
q.setParameter(0, 10);
q.setCacheable(true);
q.setCacheRegion("cache_a");//使用我们自己配置的缓存
List list = q.list();
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
B a2 = (B) iterator.next();
System.out.print(a2.getId() + "/");
}
HibernateSessionFactory.closeSession();
}</pre>
<p>&nbsp;<br />
控制台信息：</p>
<pre class="java">C:\DOCUME~1\eric\LOCALS~1\Temp\           //我的java.io.tmpdir
Hibernate: select b0_.id as id1_, b0_.bname as bname1_ from B b0_ where b0_.id&gt;?
11/14/18/25/26/27/28/29/Hibernate: select b0_.id as id1_, b0_.bname as bname1_ from B b0_ where b0_.id&gt;?
11/14/18/25/26/27/28/29/</pre>
<p>&nbsp;查看磁盘信息：</p>
<pre class="java">在文件按目录下有一下文件：
com.eric.po.B.data--------0kb
cache_a.data   ------------4 kb
org.hibernate.cache.StandardQueryCache.data  ---0kb
org.hibernate.cache.UpdateTimestampsCache.data -----0kb
</pre>
<p>&nbsp;<br />
其中&nbsp;&nbsp;&nbsp;cache_a中保存了我们的缓存文件 </p>
<p>StandardQueryCache.data 则是<span class="comments"><span style="color: #008200">&nbsp;设置默认的查询缓存的数据过期策略&nbsp;</span></span><span>&nbsp;产生的文件</span>，</p>
<p>org.hibernate.cache.UpdateTimestampsCache.data则是<span class="comments"><span style="color: #008200">&nbsp;设置时间戳缓存的数据过期策略&nbsp;</span></span></p>
<p>如果不适用我们自己的缓存配置就会使用类类的全路径路径文件（com.eric.po.B.data）来缓存我们的数据。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<br />
<br />
 <img src ="http://www.blogjava.net/freeman1984/aggbug/293871.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2009-08-24 17:09 <a href="http://www.blogjava.net/freeman1984/archive/2009/08/24/293871.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate annoation 转载</title><link>http://www.blogjava.net/freeman1984/archive/2009/08/20/293873.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 20 Aug 2009 08:57:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2009/08/20/293873.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/293873.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2009/08/20/293873.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/293873.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/293873.html</trackback:ping><description><![CDATA[<p><span style="color: #cc99ff">本文的主要内容如下：</span></p>
<p><span style="color: #cc99ff">详细解释了下面9个批注的含义及其批注所包含的属性：<br />
@MapKey<br />
@MappedSuperclass<br />
@NamedNativeQueries<br />
@NamedNativeQuery<br />
@NamedQueries<br />
@NamedQuery<br />
@OneToMany<br />
@OneToOne<br />
@OrderBy<br />
</span>■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■</p>
<p>&nbsp;</p>
<p><strong><span style="font-size: large">@MapKey</span></strong></p>
<p>默认情况下，JPA 持续性提供程序假设关联实体的主键为 java.util.Map 类型的关联的 Map 键：</p>
<p>如果主键是批注为 @Id 的非复合主键，则该字段或属性的类型实例将用作 Map 键。</p>
<p>如果主键是批注为 @IdClass 的复合主键，则主键类的实例将用作 Map 键。</p>
<p>使用 @MapKey 批注：</p>
<p>● 将某个其他字段或属性指定为 Map 键（如果关联实体的主键不适合于应用程序）</p>
<p>● 指定一个嵌入的复合主键类（请参阅 @EmbeddedId）</p>
<p>● 指定的字段或属性必须具有唯一约束（请参阅 @UniqueConstraint）。</p>
<p><strong>表 1-24</strong> 列出了此批注的属性。有关更多详细信息，请参阅 <a href="http://java.sun.com/javaee/5/docs/api/javax/persistence/MapKey.html">API</a>。</p>
<p align="center"><strong>表 1-24 @MapKey 属性</strong></p>
<p>&nbsp;</p>
<table cellspacing="0" cellpadding="3" rules="all" width="65%" align="center" border="1">
    <tbody>
        <tr valign="top" align="left">
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">属性</span></p>
            </th>
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">必需</span></p>
            </th>
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">说明</span></p>
            </th>
        </tr>
        <tr valign="top" align="left">
            <td align="left" width="10%"><span style="color: #ff99cc">name</span></td>
            <td align="left" width="10%">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/33c762fe44729a255c6008fa.jpg" border="0" /></span></p>
            </td>
            <td align="left" width="45%"><span style="color: #ff99cc"><strong>默认值</strong>：默认情况下，JPA 持续性提供程序将关联实体的主键作为 Map 键，以用于映射到非复合主键或复合主键（批注为 @IdClass）的 java.util.Map 的属性或字段。<br />
            如果要将某个其他字段或属性用作 Map 键，请将 name 设置为要使用的关联实体的 String 字段或属性名。</span></td>
        </tr>
    </tbody>
</table>
<p>在示例 1-52 中，Project 对作为 Map 的 Employee 实例拥有一对多关系。示例 1-52 显示了如何使用 @MapKey 批注指定此 Map 的键为 Employee 字段 empPK，它是一个类型为 EmployeePK（请参阅示例 1-52）的嵌入式复合主键（请参阅示例 1-51）。</p>
<p><strong>示例 1-50</strong> 使用 @MapKey 的 Project 实体</p>
<p>@Entity<br />
public class Project {<br />
&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp; @OneToMany(mappedBy="project")&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; @MapKey(name="empPK")<br />
&nbsp;&nbsp;&nbsp; public Map&lt;EmployeePK, Employee&gt; getEmployees() {<br />
&nbsp;&nbsp;&nbsp; ... <br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; ...<br />
}</p>
<p><strong>示例 1-51</strong> Employee 实体</p>
<p>@Entity<br />
public class Employee {<br />
&nbsp;&nbsp;&nbsp; @EmbeddedId<br />
&nbsp;&nbsp;&nbsp; public EmployeePK getEmpPK() {<br />
&nbsp;&nbsp;&nbsp;&nbsp; ... <br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp; @ManyToOne<br />
&nbsp;&nbsp;&nbsp; @JoinColumn(name="proj_id")<br />
&nbsp;&nbsp;&nbsp; public Project getProject() { <br />
&nbsp;&nbsp;&nbsp; ... <br />
&nbsp;&nbsp;&nbsp; }<br />
...<br />
}</p>
<p><strong>示例 1-52</strong> EmployeePK 复合主键类</p>
<p>@Embeddable<br />
public class EmployeePK {<br />
&nbsp;&nbsp;&nbsp; String name;<br />
&nbsp;&nbsp;&nbsp; Date birthDate;<br />
}</p>
<p><strong><span style="font-size: large">@MappedSuperclass</span></strong></p>
<p>默认情况下，JPA 持续性提供程序假设实体的所有持久字段均在该实体中定义。</p>
<p>使用 @MappedSuperclass 批注指定一个实体类从中继承持久字段的超类。当多个实体类共享通用的持久字段或属性时，这将是一个方便的模式。</p>
<p>您可以像对实体那样使用任何直接和关系映射批注（如 @Basic 和 @ManyToMany）对该超类的字段和属性进行批注，但由于没有针对该超类本身的表存在，因此这些映射只适用于它的子类。继承的持久字段或属性属于子类的表。</p>
<p>可以在子类中使用 @AttributeOverride 或 @AssociationOverride 批注来覆盖超类的映射配置。</p>
<p>该批注没有属性。有关更多详细信息，请参阅 <a href="http://java.sun.com/javaee/5/docs/api/javax/persistence/EmbeddableSuperclass.html">API</a>。</p>
<p>示例 1-53 显示了如何使用此批注将 Employee 指定为映射超类。示例 1-54 显示了如何扩展实体中的此超类，以及如何在实体类中使用 @AttributeOverride 以覆盖超类中设置的配置。</p>
<p><strong>示例 1-53</strong> @MappedSuperclass</p>
<p>@MappedSuperclass<br />
public class Employee {<br />
@Id<br />
protected Integer empId;<br />
<br />
@Version<br />
protected Integer version;<br />
<br />
@ManyToOne<br />
@JoinColumn(name="ADDR")<br />
protected Address address;<br />
<br />
public Integer getEmpId() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
public void setEmpId(Integer id) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ... <br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
public Address getAddress() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ... <br />
&nbsp;&nbsp;&nbsp; }<br />
<br />
public void setAddress(Address addr) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ... <br />
&nbsp;&nbsp;&nbsp; }<br />
}</p>
<p><strong>示例 1-54</strong> 扩展 @MappedSuperclass</p>
<p>@Entity<br />
@AttributeOverride(name="address", column=@Column(name="ADDR_ID"))<br />
public class PartTimeEmployee extends Employee {</p>
<p>@Column(name="WAGE")<br />
protected Float hourlyWage;</p>
<p>public PartTimeEmployee() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp; }</p>
<p>public Float getHourlyWage() { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ... <br />
&nbsp;&nbsp;&nbsp; }</p>
<p>public void setHourlyWage(Float wage) { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ... <br />
&nbsp;&nbsp;&nbsp; }<br />
}</p>
<p><br />
<strong><span style="font-size: large">@NamedNativeQueries</span></strong></p>
<p>如果需要指定多个 @NamedNativeQuery，则必须使用一个 @NamedNativeQueries 批注指定所有命名查询。</p>
<p><strong>表 1-25</strong> 列出了此批注的属性。有关更多详细信息，请参阅 <a href="http://java.sun.com/javaee/5/docs/api/javax/persistence/NamedNativeQueries.html">API</a>。</p>
<p align="center"><strong>表 1-25 @NamedNativeQueries 属性</strong></p>
<p>&nbsp;</p>
<table cellspacing="0" cellpadding="3" rules="all" width="65%" align="center" border="1">
    <tbody>
        <tr valign="top" align="left">
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">属性</span></p>
            </th>
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">必需</span></p>
            </th>
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">说明</span></p>
            </th>
        </tr>
        <tr valign="top" align="left">
            <td align="left" width="10%"><span style="color: #ff99cc">value</span></td>
            <td align="left" width="10%">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/284858b419c208678bd4b212.jpg" border="0" /></span></p>
            </td>
            <td align="left" width="45%"><span style="color: #ff99cc">要指定两个或更多属性覆盖，请将 value 设置为 NamedNativeQuery 实例数组（请参阅 @NamedNativeQuery）。</span></td>
        </tr>
    </tbody>
</table>
<p>示例 1-55 显示了如何使用此批注指定两个命名原生查询。</p>
<p><strong>示例 1-55</strong> @NamedNativeQueries</p>
<p>@Entity<br />
@NamedNativeQueries({<br />
@NamedNativeQuery(<br />
name="findAllPartTimeEmployees",<br />
query="SELECT * FROM EMPLOYEE WHERE PRT_TIME=1"<br />
&nbsp;&nbsp;&nbsp; ),<br />
@NamedNativeQuery(<br />
name="findAllSeasonalEmployees",<br />
query="SELECT * FROM EMPLOYEE WHERE SEASON=1"<br />
&nbsp;&nbsp;&nbsp; )<br />
})<br />
public class PartTimeEmployee extends Employee {<br />
&nbsp;&nbsp;&nbsp; ...<br />
}</p>
<p><br />
<strong><span style="font-size: large">@NamedNativeQuery</span></strong></p>
<p>在使用 JPA 持续性提供程序的应用程序中，可以使用实体管理器动态创建和执行查询，也可以预定义查询并在运行时按名称执行。</p>
<p>使用 @NamedNativeQuery 批注创建与 @Entity 或 @MappedSuperclass 关联的预定义查询，这些查询：</p>
<p>● 使用基础数据库的原生 SQL</p>
<p>● 经常被使用</p>
<p>● 比较复杂并且难于创建</p>
<p>● 可以在不同实体之间共享</p>
<p>● 返回实体、标量值或两者的组合（另请参阅 @ColumnResult、@EntityResult、@FieldResult 和@SqlResultSetMapping）</p>
<p>如果有多个要定义的 @NamedNativeQuery，则必须使用 @NamedNativeQueries。</p>
<p>要预定义适合于任何数据库的可移植查询，请参阅 @NamedQuery。</p>
<p><strong>表 1-26</strong> 列出了此批注的属性。有关更多详细信息，请参阅 <a href="http://java.sun.com/javaee/5/docs/api/javax/persistence/NamedNativeQuery.html">API</a>。</p>
<p align="center"><strong>表 1-26 @NamedNativeQuery 属性<br />
</strong></p>
<p>&nbsp;</p>
<table cellspacing="0" cellpadding="3" rules="all" width="65%" align="center" border="1">
    <tbody>
        <tr valign="top" align="left">
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">属性</span></p>
            </th>
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">必需</span></p>
            </th>
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">说明</span></p>
            </th>
        </tr>
        <tr valign="top" align="left">
            <td align="left" width="10%"><span style="color: #ff99cc">query</span></td>
            <td align="left" width="10%">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/284858b419c208678bd4b212.jpg" border="0" /></span></p>
            </td>
            <td align="left" width="45%"><span style="color: #ff99cc">要指定查询，请将 query 设置为 SQL 查询（作为 String）。<br />
            有关原生 SQL 查询语言的详细信息，请参阅数据库文档。</span></td>
        </tr>
        <tr valign="top" align="left">
            <td align="left"><span style="color: #ff99cc">hints</span></td>
            <td align="left">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/33c762fe44729a255c6008fa.jpg" border="0" /></span></p>
            </td>
            <td align="left"><span style="color: #ff99cc"><strong>默认值</strong>：空 QueryHint 数组。<br />
            默认情况下，JPA 持续性提供程序假设 SQL 查询应完全按照 query 属性提供的方式执行。<br />
            要微调查询的执行，可以选择将 hints 设置为一个 QueryHint 数组（请参阅 @QueryHint）。在执行时，EntityManager 将向基础数据库传递提示。</span></td>
        </tr>
        <tr valign="top" align="left">
            <td align="left"><span style="color: #ff99cc">name</span></td>
            <td align="left">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/284858b419c208678bd4b212.jpg" border="0" /></span></p>
            </td>
            <td align="left"><span style="color: #ff99cc">要指定查询名称，请将 name 设置为所需的 String 名称。<br />
            这是您在运行时调用查询所使用的名称（请参阅示例 1-56）。</span></td>
        </tr>
        <tr valign="top" align="left">
            <td align="left"><span style="color: #ff99cc">resultClass</span></td>
            <td align="left">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/33c762fe44729a255c6008fa.jpg" border="0" /></span></p>
            </td>
            <td align="left"><span style="color: #ff99cc"><strong>默认值</strong>：JPA 持续性提供程序假设结果类是关联实体的 Class。<br />
            要指定结果类，请将 resultClass 设置为所需的 Class。</span></td>
        </tr>
        <tr valign="top" align="left">
            <td align="left"><span style="color: #ff99cc">resultSetMapping</span></td>
            <td align="left">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/33c762fe44729a255c6008fa.jpg" border="0" /></span></p>
            </td>
            <td align="left"><span style="color: #ff99cc"><strong>默认值</strong>：JPA 持续性提供程序假设原生 SQL 查询中的 SELECT 语句：返回一个类型的实体；包括与返回的实体的所有字段或属性相对应的所有列；并使用与字段或属性名称（未使用 AS 语句）相对应的列名。<br />
            要控制 JPA 持续性提供程序如何将 JDBC 结果集映射到实体字段或属性以及标量，请通过将 resultSetMapping 设置为所需的 @SqlResultSetMapping 的 String 名称来指定结果集映射。</span></td>
        </tr>
    </tbody>
</table>
<p>示例 1-56 显示了如何使用 @NamedNativeQuery 批注定义一个使用基础数据库的原生 SQL 的查询。示例 1-57 显示了如何使用 EntityManager 获取此查询以及如何通过 Query 方法 getResultList 执行该查询。</p>
<p><strong>示例 1-56</strong> 使用 @NamedNativeQuery 实现一个 Oracle 层次查询</p>
<p>@Entity<br />
@NamedNativeQuery(<br />
name="findAllEmployees",<br />
query="SELECT * FROM EMPLOYEE"<br />
)<br />
public class Employee implements Serializable {<br />
&nbsp;&nbsp;&nbsp; ...<br />
}</p>
<p><strong>示例 1-57</strong> 执行一个命名原生查询</p>
<p>Query queryEmployees = em.createNamedQuery("findAllEmployees");<br />
Collection employees = queryEmployees.getResultList();</p>
<p><strong><span style="font-size: large">@NamedQueries</span></strong></p>
<p>如果需要指定多个 @NamedQuery，则必须使用一个 @NamedQueries 批注指定所有命名查询。</p>
<p><strong>表 1-27</strong> 列出了此批注的属性。有关更多详细信息，请参阅 <a href="http://java.sun.com/javaee/5/docs/api/javax/persistence/NamedQueries.html">API</a>。</p>
<p align="center"><strong>表 1-27 @NamedQueries 属性<br />
</strong></p>
<p>&nbsp;</p>
<table cellspacing="0" cellpadding="3" rules="all" width="65%" align="center" border="1">
    <tbody>
        <tr valign="top" align="left">
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">属性</span></p>
            </th>
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">必需</span></p>
            </th>
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">说明</span></p>
            </th>
        </tr>
        <tr valign="top" align="left">
            <td align="left" width="10%"><span style="color: #ff99cc">value</span></td>
            <td align="left" width="10%">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/284858b419c208678bd4b212.jpg" border="0" /></span></p>
            </td>
            <td align="left" width="45%"><span style="color: #ff99cc">要指定两个或更多属性覆盖，请将 value 设置为 NamedQuery 实例数组（请参阅 @NamedQuery）。</span></td>
        </tr>
    </tbody>
</table>
<p>示例 1-58 显示了如何使用此批注指定两个命名查询。</p>
<p><strong>示例 1-58</strong> @NamedQueries</p>
<p>@Entity<br />
@NamedQueries({<br />
@NamedQuery(<br />
name="findAllEmployeesByFirstName",<br />
query="SELECT OBJECT(emp) FROM Employee emp WHERE emp.firstName = :firstname"<br />
&nbsp;&nbsp;&nbsp; ),<br />
@NamedQuery(<br />
name="findAllEmployeesByLasttName",<br />
query="SELECT OBJECT(emp) FROM Employee emp WHERE emp.lasstName = :lastname"<br />
&nbsp;&nbsp;&nbsp; )<br />
})<br />
public class PartTimeEmployee extends Employee {<br />
&nbsp;&nbsp;&nbsp; ...<br />
}</p>
<p><strong><span style="font-size: large">@NamedQuery</span></strong></p>
<p>在使用 JPA 持续性提供程序的应用程序中，可以使用实体管理器动态创建和执行查询，也可以预定义查询并在运行时按名称执行。</p>
<p>使用 @NamedQuery 批注创建与 @Entity 或 @MappedSuperclass 关联的预定义查询，这些查询：</p>
<p>● 使用 JPA 查询语言（请参阅 <a href="http://jcp.org/aboutJava/communityprocess/pfd/jsr220/index.html">JSR-000220 Enterprise JavaBeans v3.0</a> 规范，第 4 章）进行基于任何基础数据库的可移植执行</p>
<p>● 经常被使用</p>
<p>● 比较复杂并且难于创建</p>
<p>● 可以在不同实体之间共享</p>
<p>● 只返回实体（从不返回标量值），并只返回一个类型的实体</p>
<p>如果有多个要定义的 @NamedQuery，则必须使用 @NamedQueries。</p>
<p>要在已知的基础数据库中预定义原生 SQL 查询，请参阅 @NamedNativeQuery。使用原生 SQL 查询，您可以返回实体（包括不同类型的实体）、标量值或同时返回两者。</p>
<p><strong>表 1-28</strong> 列出了此批注的属性。有关更多详细信息，请参阅 <a href="http://java.sun.com/javaee/5/docs/api/javax/persistence/NamedQuery.html">API</a>。</p>
<p align="center"><strong>表 1-28 @NamedQuery 属性<br />
</strong></p>
<p>&nbsp;</p>
<table cellspacing="0" cellpadding="3" rules="all" width="65%" align="center" border="1">
    <tbody>
        <tr valign="top" align="left">
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">属性</span></p>
            </th>
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">必需</span></p>
            </th>
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">说明</span></p>
            </th>
        </tr>
        <tr valign="top" align="left">
            <td align="left" width="10%"><span style="color: #ff99cc">query</span></td>
            <td align="left" width="10%">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/284858b419c208678bd4b212.jpg" border="0" /></span></p>
            </td>
            <td align="left" width="45%"><span style="color: #ff99cc">要指定查询，请将 query 设置为 JPA 查询语言（作为 String）。<br />
            有关 JPA 查询语言的详细信息，请参阅 </span><a href="http://jcp.org/aboutJava/communityprocess/pfd/jsr220/index.html"><span style="text-decoration: underline"><span style="color: #ff99cc">JSR-000220 Enterprise JavaBeans v.3.0</span></span></a><span style="color: #ff99cc"> 规范的第 4 章。</span> </td>
        </tr>
        <tr valign="top" align="left">
            <td align="left"><span style="color: #ff99cc">hints</span></td>
            <td align="left">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/33c762fe44729a255c6008fa.jpg" border="0" /></span></p>
            </td>
            <td align="left"><span style="color: #ff99cc"><strong>默认值</strong>：空 QueryHint 数组。<br />
            默认情况下，JPA 持续性提供程序假设 SQL 查询应完全按照 query 属性提供的方式执行，而不管基础数据库如何。<br />
            如果您知道基础数据库在运行时的状态，则要微调查询的执行，可以选择将 hints 设置为 QueryHint 数组（请参阅 @QueryHint）。在执行时，EntityManager 将向基础数据库传递提示。</span></td>
        </tr>
        <tr valign="top" align="left">
            <td align="left"><span style="color: #ff99cc">name</span></td>
            <td align="left">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/284858b419c208678bd4b212.jpg" border="0" /></span></p>
            </td>
            <td align="left"><span style="color: #ff99cc">要指定查询名称，请将 name 设置为查询名称（作为 String）。<br />
            这是您在运行时调用查询所使用的名称（请参阅示例 1-59）。</span></td>
        </tr>
    </tbody>
</table>
<p>示例 1-59 显示了如何使用 @NamedQuery 批注定义一个JPA 查询语言查询，该查询使用名为 firstname 的参数。示例 1-60 显示了如何使用 EntityManager 获取此查询并使用 Query 方法 setParameter 设置 firstname 参数。</p>
<p><strong>示例 1-59</strong> 使用 @NamedQuery 实现一个带参数的查询</p>
<p>@Entity<br />
@NamedQuery(<br />
name="findAllEmployeesByFirstName",<br />
query="SELECT OBJECT(emp) FROM Employee emp WHERE emp.firstName = :firstname"<br />
)<br />
public class Employee implements Serializable {<br />
&nbsp;&nbsp;&nbsp; ...<br />
}</p>
<p><strong>示例 1-60</strong> 执行命名查询</p>
<p>Query queryEmployeesByFirstName = em.createNamedQuery("findAllEmployeesByFirstName");<br />
queryEmployeeByFirstName.setParameter("firstName", "John");<br />
Collection employees = queryEmployessByFirstName.getResultList();</p>
<p><strong><span style="font-size: large">@OneToMany</span></strong></p>
<p>默认情况下，JPA 为具有一对多多重性的多值关联定义一个 OneToMany 映射。</p>
<p>使用 @OneToMany 批注：</p>
<p>● 将获取类型配置为 LAZY</p>
<p>● 由于所使用的 Collection 不是使用一般参数定义的，因此配置关联的目标实体</p>
<p>● 配置必须层叠到关联目标的操作：例如，如果删除了拥有实体，则确保还删除关联的目标</p>
<p>● 配置持续性提供程序对单向一对多关系使用的连接表（请参阅 @JoinTable）的详细信息</p>
<p><strong>表 1-29</strong> 列出了此批注的属性。有关更多详细信息，请参阅 <a href="http://java.sun.com/javaee/5/docs/api/javax/persistence/OneToMany.html">API</a>。</p>
<p align="center"><strong>表 1-29 @OneToMany 属性</strong></p>
<p>&nbsp;</p>
<table cellspacing="0" cellpadding="3" rules="all" width="65%" align="center" border="1">
    <tbody>
        <tr valign="top" align="left">
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">属性</span></p>
            </th>
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">必需</span></p>
            </th>
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">说明</span></p>
            </th>
        </tr>
        <tr valign="top" align="left">
            <td align="left" width="10%"><span style="color: #ff99cc">cascade<br />
            </span></td>
            <td align="left" width="10%">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/33c762fe44729a255c6008fa.jpg" border="0" /></span></p>
            </td>
            <td align="left" width="45%"><span style="color: #ff99cc"><strong>默认值</strong>：CascadeType 的空数组。<br />
            默认情况下，JPA 不会将任何持续性操作层叠到关联的目标。<br />
            如果希望某些或所有持续性操作层叠到关联的目标，请将 cascade 设置为一个或多个 CascadeType 实例，其中包括：<br />
            ● ALL - 针对拥有实体执行的任何持续性操作均层叠到关联的目标。<br />
            ● MERGE - 如果合并了拥有实体，则将 merge 层叠到关联的目标。<br />
            ● PERSIST - 如果持久保存拥有实体，则将 persist 层叠到关联的目标。<br />
            ● REFRESH - 如果刷新了拥有实体，则 refresh 为关联的层叠目标。<br />
            ● REMOVE - 如果删除了拥有实体，则还删除关联的目标。</span></td>
        </tr>
        <tr valign="top" align="left">
            <td align="left" width="10%"><br />
            <span style="color: #ff99cc">fetch</span> </td>
            <td align="left" width="10%">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/33c762fe44729a255c6008fa.jpg" border="0" /></span></p>
            </td>
            <td align="left" width="45%"><span style="color: #ff99cc"><strong>默认值</strong>：FetchType.EAGER。<br />
            默认情况下，JPA 持续性提供程序使用获取类型 EAGER：它要求持续性提供程序运行时必须急性获取数据。<br />
            如果这不适合于应用程序或特定的持久字段，请将 fetch 设置为 FetchType.LAZY：它提示持续性提供程序在首次访问数据（如果可以）时应惰性获取数据。</span></td>
        </tr>
        <tr valign="top" align="left">
            <td align="left" width="10%"><span style="color: #ff99cc">mappedBy</span></td>
            <td align="left" width="10%">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/33c762fe44729a255c6008fa.jpg" border="0" /></span></p>
            </td>
            <td align="left" width="45%"><span style="color: #ff99cc"><strong>默认值</strong>：如果关系是单向的，则该持续性提供程序确定拥有该关系的字段。<br />
            如果关系是双向的，则将关联相反（非拥有）方上的 mappedBy 元素设置为拥有此关系的字段或属性的名称（如示例 1-61 所示）。</span></td>
        </tr>
        <tr valign="top" align="left">
            <td align="left" width="10%"><span style="color: #ff99cc">targetEntity</span></td>
            <td align="left" width="10%">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/33c762fe44729a255c6008fa.jpg" border="0" /></span></p>
            </td>
            <td align="left" width="45%"><span style="color: #ff99cc"><span style="color: #ff99cc"><strong>默认值</strong>：使用一般参数定义的 Collection 的参数化类型。<br />
            默认情况下，如果使用通过一般参数定义的 Collection，则持续性提供程序将从被引用的对象类型推断出关联的目标实体。<br />
            如果 Collection 不使用一般参数，则必须指定作为关联目标的实体类：将关联拥有方上的 targetEntity 元素设</span>置为作为关系目标的实体的 Class。</span></td>
        </tr>
    </tbody>
</table>
<p>示例 1-61 和示例 1-62 显示了如何使用此批注在使用一般参数的 Customer（被拥有方）和 Order（拥有方）之间配置一个一对多映射。</p>
<p><strong>示例 1-61</strong> @OneToMany - 使用一般参数的 Customer 类</p>
<p>@Entity<br />
public class Customer implements Serializable {<br />
&nbsp;&nbsp;&nbsp; ...<br />
@OneToMany(cascade=ALL, mappedBy="customer")<br />
public Set&lt;Order&gt; getOrders() { <br />
return orders; <br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; ...<br />
}</p>
<p><strong>示例 1-62</strong> @ManyToOne - 使用一般参数的 Order 类</p>
<p>@Entity<br />
public class Customer implements Serializable {<br />
&nbsp;&nbsp;&nbsp; ...<br />
@ManyToOne<br />
@JoinColumn(name="CUST_ID", nullable=false)<br />
public Customer getCustomer() {<br />
return customer;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; ...<br />
}</p>
<p><br />
<strong><span style="font-size: large">@OneToOne</span></strong></p>
<p>默认情况下，JPA 为指向另一个具有一对一多重性的实体的单值关联定义一个 OneToOne 映射，并从被引用的对象类型推断出关联的目标实体。</p>
<p>使用 @OneToOne 批注：</p>
<p>● 将获取类型配置为 LAZY</p>
<p>● 如果空值不适合于应用程序，则将映射配置为禁止空值（针对非基元类型）</p>
<p>● 配置关联的目标实体（如果无法从被引用的对象类型推断出它）</p>
<p>● 配置必须层叠到关联目标的操作：例如，如果删除了拥有实体，则确保还删除关联的目标</p>
<p><strong>表 1-30</strong> 列出了此批注的属性。有关更多详细信息，请参阅 <a href="http://java.sun.com/javaee/5/docs/api/javax/persistence/OneToOne.html">API</a>。</p>
<p align="center"><strong>表 1-30 @OneToOne 属性</strong></p>
<p>&nbsp;</p>
<table cellspacing="0" cellpadding="3" rules="all" width="65%" align="center" border="1">
    <tbody>
        <tr valign="top" align="left">
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">属性</span></p>
            </th>
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">必需</span></p>
            </th>
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">说明</span></p>
            </th>
        </tr>
        <tr valign="top" align="left">
            <td align="left" width="10%"><span style="color: #ff99cc">cascade<br />
            </span></td>
            <td align="left" width="10%">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/33c762fe44729a255c6008fa.jpg" border="0" /></span></p>
            </td>
            <td align="left" width="45%"><span style="color: #ff99cc"><strong>默认值</strong>：CascadeType 的空数组。<br />
            默认情况下，JPA 不会将任何持续性操作层叠到关联的目标。<br />
            如果希望某些或所有持续性操作层叠到关联的目标，请将 cascade 设置为一个或多个 CascadeType 实例，其中包括：<br />
            ● ALL - 针对拥有实体执行的任何持续性操作均层叠到关联的目标。<br />
            ● MERGE - 如果合并了拥有实体，则将 merge 层叠到关联的目标。<br />
            ● PERSIST - 如果持久保存拥有实体，则将 persist 层叠到关联的目标。<br />
            ● REFRESH - 如果刷新了拥有实体，则 refresh 为关联的层叠目标。<br />
            ● REMOVE - 如果删除了拥有实体，则还删除关联的目标。</span></td>
        </tr>
        <tr valign="top" align="left">
            <td align="left" width="10%"><br />
            <span style="color: #ff99cc">fetch</span> </td>
            <td align="left" width="10%">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/33c762fe44729a255c6008fa.jpg" border="0" /></span></p>
            </td>
            <td align="left" width="45%"><span style="color: #ff99cc"><strong>默认值</strong>：FetchType.EAGER。<br />
            默认情况下，JPA 持续性提供程序使用获取类型 EAGER：它要求持续性提供程序运行时必须急性获取数据。<br />
            如果这不适合于应用程序或特定的持久字段，请将 fetch 设置为 FetchType.LAZY：它提示持续性提供程序在首次访问数据（如果可以）时应惰性获取数据。</span></td>
        </tr>
        <tr valign="top" align="left">
            <td align="left" width="10%"><span style="color: #ff99cc">mappedBy</span></td>
            <td align="left" width="10%">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/33c762fe44729a255c6008fa.jpg" border="0" /></span></p>
            </td>
            <td align="left" width="45%"><span style="color: #ff99cc"><strong>默认值</strong>：如果关系是单向的，则该持续性提供程序确定拥有该关系的字段。<br />
            如果关系是双向的，则将关联相反（非拥有）方上的 mappedBy 元素设置为拥有此关系的字段或属性的名称（如示例 1-64 所示）。</span></td>
        </tr>
        <tr valign="top" align="left">
            <td align="left" width="10%"><span style="color: #ff99cc; font-family: NSimsun">
            <p><code>optional</code></p>
            </span></td>
            <td align="left" width="10%">
            <p align="center"><span style="color: #ff99cc; font-family: NSimsun"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/33c762fe44729a255c6008fa.jpg" border="0" /></span></p>
            </td>
            <td align="left" width="45%"><span style="color: #ff99cc"><strong>默认值</strong>：true。<br />
            默认情况下，JPA 持续性提供程序假设所有（非基元）字段和属性的值可以为空。<br />
            如果这并不适合于您的应用程序，请将 optional 设置为 false。</span></td>
        </tr>
        <tr valign="top" align="left">
            <td align="left" width="10%"><span style="color: #ff99cc">targetEntity</span></td>
            <td align="left" width="10%">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/33c762fe44729a255c6008fa.jpg" border="0" /></span></p>
            </td>
            <td align="left" width="45%"><span style="color: #ff99cc"><strong>默认值</strong>：JPA 持续性提供程序从被引用的对象类型推断出关联的目标实体。<br />
            如果持续性提供程序无法推断出目标实体的类型，则将关联的拥有方上的 targetEntity 元素设置为作为关系目标的实体的 Class。</span></td>
        </tr>
    </tbody>
</table>
<p>示例 1-63 和示例 1-64 显示了如何使用此批注在 Customer（拥有方）和 CustomerRecord（被拥有方）之间配置一个一对一映射。</p>
<p><strong>示例 1-63</strong> @OneToOne - Customer 类</p>
<p>@Entity<br />
public class Customer implements Serializable {<br />
&nbsp;&nbsp;&nbsp; ...<br />
@OneToOne(optional=false)<br />
@JoinColumn(name="CUSTREC_ID", unique=true, nullable=false, updatable=false)<br />
public CustomerRecord getCustomerRecord() { <br />
return customerRecord; <br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; ...<br />
}</p>
<p><strong>示例 1-64</strong> @OneToOne - CustomerRecord 类</p>
<p>@Entity<br />
public class CustomerRecord implements Serializable {<br />
&nbsp;&nbsp;&nbsp; ...<br />
@OneToOne(optional=false, mappedBy="customerRecord")<br />
public Customer getCustomer() {<br />
return customer;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; ...<br />
}</p>
<p><br />
<strong><span style="font-size: large">@OrderBy</span></strong></p>
<p>默认情况下，JPA 持续性提供程序按关联实体的主键以升序顺序检索 Collection 关联的成员。</p>
<p>将 @OrderBy 批注与 @OneToMany 和 @ManyToMany 一起使用以便：</p>
<p>● 指定一个或多个作为排序依据的其他字段或属性</p>
<p>● 为每个这样的字段或属性名指定不同的排序（升序或降序）</p>
<p><strong>表 1-31</strong> 列出了此批注的属性。有关更多详细信息，请参阅 <a href="http://java.sun.com/javaee/5/docs/api/javax/persistence/OrderBy.html">API</a>。</p>
<p align="center"><strong>表 1-31 @OrderBy 属性<br />
</strong></p>
<p>&nbsp;</p>
<table cellspacing="0" cellpadding="3" rules="all" width="65%" align="center" border="1">
    <tbody>
        <tr valign="top" align="left">
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">属性</span></p>
            </th>
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">必需</span></p>
            </th>
            <th valign="bottom" align="left">
            <p align="center"><span style="color: #ff99cc">说明</span></p>
            </th>
        </tr>
        <tr valign="top" align="left">
            <td align="left" width="10%"><span style="color: #ff99cc">value</span></td>
            <td align="left" width="10%">
            <p align="center"><span style="color: #ff99cc"><img class="blogimg" alt="" src="http://hiphotos.baidu.com/shirdrn/pic/item/33c762fe44729a255c6008fa.jpg" border="0" /></span></p>
            </td>
            <td align="left" width="45%"><span style="color: #ff99cc"><strong>默认值</strong>：JPA 持续性提供程序按关联实体的主键以升序顺序检索 Collection 关联的成员。<br />
            如果要按某些其他字段或属性排序并指定了不同的排序，则将 value 设置为以下元素的逗号分隔列表："property-or-field-name ASC|DESC&#8221;（请参阅示例 1-65）。</span></td>
        </tr>
    </tbody>
</table>
<p>示例 1-65 显示了如何使用 @OrderBy 批注指定 Project 方法 getEmployees 应按 Employee 字段 lastname 以升序顺序并按 Employee 字段 seniority 以降序顺序返回 Employee 的 List。示例 1-66 显示了默认情况下，Employee 方法 getProjects 按 Employee 主键 empId 以升序顺序返回 List。</p>
<p><strong>示例 1-65</strong> Project 实体</p>
<p>@Entity public class Project {<br />
&nbsp;&nbsp;&nbsp; ...<br />
@ManyToMany<br />
@OrderBy("lastname ASC", "seniority DESC")<br />
public List&lt;Employee&gt; getEmployees() {<br />
&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp; };<br />
&nbsp;&nbsp;&nbsp; ...<br />
}</p>
<p><strong>示例 1-66</strong> Employee 实体</p>
<p>@Entity public class Employee {<br />
@Id<br />
private int empId;<br />
&nbsp;&nbsp;&nbsp; ...<br />
private String lastname;<br />
&nbsp;&nbsp;&nbsp; ...<br />
private int seniority;<br />
&nbsp;&nbsp;&nbsp; ...<br />
@ManyToMany(mappedBy="employees")<br />
// By default, returns a List in ascending order by empId<br />
public List&lt;Project&gt; getProjects() {<br />
&nbsp;&nbsp;&nbsp; ...<br />
&nbsp;&nbsp;&nbsp; };<br />
&nbsp;&nbsp;&nbsp; ...<br />
}</p>
<br />
<br />
 <img src ="http://www.blogjava.net/freeman1984/aggbug/293873.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2009-08-20 16:57 <a href="http://www.blogjava.net/freeman1984/archive/2009/08/20/293873.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hibernate annoation (九 cascading)</title><link>http://www.blogjava.net/freeman1984/archive/2009/08/20/293874.html</link><dc:creator>疯狂</dc:creator><author>疯狂</author><pubDate>Thu, 20 Aug 2009 08:03:00 GMT</pubDate><guid>http://www.blogjava.net/freeman1984/archive/2009/08/20/293874.html</guid><wfw:comment>http://www.blogjava.net/freeman1984/comments/293874.html</wfw:comment><comments>http://www.blogjava.net/freeman1984/archive/2009/08/20/293874.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/freeman1984/comments/commentRss/293874.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/freeman1984/services/trackbacks/293874.html</trackback:ping><description><![CDATA[<p>1，cascade=CascadeType.PERSIST</p>
<p>当调用session的session.persist(object)时会产生级联保存 （不是save方法或者其他）</p>
<p>2，cascade=CascadeType.MERGE</p>
<p>&nbsp;当调用session的session.merge(object)时会产生级联合并 如果内存没有此对象表现为级联保存</p>
<p>3，cascade=CascadeType.REMOVE</p>
<p>当调用session的session.delete时会产生级联删除 需要关联方和被关联的具有id（先get）</p>
<p>4，cascade=CascadeType.REFRESH （底层数据库和内存不一致是使用表现为异常Found two representations of same collection）</p>
<p>当调用session的session.refresh时会产生级查询 从而达到更新数据库的目的</p>
<p>5，cascade=CascadeType.ALL</p>
<p>以上所有</p>
<br />
<br />
 <img src ="http://www.blogjava.net/freeman1984/aggbug/293874.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/freeman1984/" target="_blank">疯狂</a> 2009-08-20 16:03 <a href="http://www.blogjava.net/freeman1984/archive/2009/08/20/293874.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>