﻿<?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-AllBlue-文章分类-Hibernate</title><link>http://www.blogjava.net/lzn1446/category/43256.html</link><description /><language>zh-cn</language><lastBuildDate>Thu, 28 Jul 2011 23:06:57 GMT</lastBuildDate><pubDate>Thu, 28 Jul 2011 23:06:57 GMT</pubDate><ttl>60</ttl><item><title>【转】hibernate lazy(延迟加载）</title><link>http://www.blogjava.net/lzn1446/articles/354970.html</link><dc:creator>blue_leo</dc:creator><author>blue_leo</author><pubDate>Mon, 25 Jul 2011 03:42:00 GMT</pubDate><guid>http://www.blogjava.net/lzn1446/articles/354970.html</guid><wfw:comment>http://www.blogjava.net/lzn1446/comments/354970.html</wfw:comment><comments>http://www.blogjava.net/lzn1446/articles/354970.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lzn1446/comments/commentRss/354970.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lzn1446/services/trackbacks/354970.html</trackback:ping><description><![CDATA[<div>hibernate lazy(延迟加载）              			<div id="appShareOpt">                                              </div>               	                    <p>hibernate lazy策略可以使用在：<br /> * &lt;class&gt;标签上，可以取值：true/false ，在hibernate3以上版本，默认是true<br /> * &lt;property&gt;标签上，可以取值：true/false需要类增强工具<br /> * &lt;set&gt;&lt;list&gt;标签上，可以取值：true/false/extra<br /> * &lt;one-to-one&gt;&lt;many-to-one&gt;单端关联上，可以取值：false/proxy/no-proxy<br /> <br /> <strong>lazy概念：只有真正使用该对象时，才会创建，对于hibernate而言，正真使用的时候才会发出sql</strong></p> <p>hibernate支持lazy策略只有在session打开状态下有效</p> <p> </p>  <p><strong>=====================================================</strong></p> <p><strong>1. &lt;class&gt;标签上:</strong></p> <p><strong>hbm</strong></p> <p><strong>group.hbm.xml</strong></p> <p>&lt;?xml version="1.0" encoding="utf-8"?&gt;<br /> &lt;!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"<br /> "<a href="http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd</a>"&gt;<br /> &lt;hibernate-mapping package="com.model"&gt;<br /> &nbsp;&nbsp;&nbsp;  &lt;class name="Group" table="group5" lazy="true" &gt; //lazy，默认true，可不写<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;id name="id" column="id" type="java.lang.Integer"&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;generator class="native" /&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;/id&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;property name="name" column="name" length="50" type="java.lang.String" /&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  <br /> &nbsp;&nbsp;&nbsp;  &lt;/class&gt;<br /> <br /> &lt;/hibernate-mapping&gt;</p> <p><strong>测试用例：</strong></p> <p>public class LazyTest extends TestCase {<br /> <br /> public void testLoad1(){<br /> &nbsp;&nbsp;  Session session = null;<br /> &nbsp;&nbsp;  Transaction ta = null;<br /> &nbsp;&nbsp;  try{<br /> &nbsp;&nbsp;&nbsp;  session = HibernateUtil.getSession();<br /> &nbsp;&nbsp;&nbsp;  ta = session.beginTransaction();</p> <p>&nbsp;&nbsp;&nbsp;  Group g2 = (Group) session.load(Group.class, 1); //还没发出sql，lazy起延迟作用,若lazy=false,则发出sql<br /> //&nbsp;&nbsp;&nbsp;  Group g2 = (Group) session.get(Group.class, 1); //不支持lazy<br /> &nbsp;&nbsp;&nbsp;  System.out.println("group.id=" + g2.getId()); //还没发出sql，<br /> &nbsp;&nbsp;&nbsp;  System.out.println("group.name=" + g2.getName()); //发出sql<br /> &nbsp;&nbsp;&nbsp;  ta.commit();<br /> &nbsp;&nbsp;  }catch(Exception e){<br /> &nbsp;&nbsp;&nbsp;  e.printStackTrace();<br /> &nbsp;&nbsp;&nbsp;  if(ta != null){<br /> &nbsp;&nbsp;&nbsp;&nbsp;  ta.rollback();<br /> &nbsp;&nbsp;&nbsp;  }<br /> &nbsp;&nbsp;  }finally{<br /> &nbsp;&nbsp;&nbsp;  //关闭session， user变为detached离线对象<br /> &nbsp;&nbsp;&nbsp;  HibernateUtil.closeSession(session);<br /> &nbsp;&nbsp;  }<br /> &nbsp;&nbsp;  //System.out.println("group.name=" + g2.getName()); //hibernate支持lazy策略只有在session打开状态下有效,所以此出Exception<br /> }<br /> </p> <p>}</p> <p> </p> <p> </p>  <p><strong>&lt;class&gt;标签上的lazy特性只对普通属性起作用</strong></p> <p><strong>&lt;class&gt;标签上的lazy不会影响到单端关联上的lazy特性</strong></p> <p>＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝</p> <p><strong>2.&lt;set&gt;&lt;list&gt;标签上</strong>，可以取值：true/false/extra，默认是true</p> <p>hbm.xml</p> <p>Classes.hbm.xml</p> <p>&lt;?xml version="1.0" encoding="utf-8"?&gt;<br /> &lt;!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"<br /> "<a href="http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd</a>"&gt;<br /> &lt;hibernate-mapping package="com.zd.model"&gt;<br /> &nbsp;&nbsp;&nbsp;  &lt;class name="Classes" table="classes" &gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;id name="id" column="id" type="java.lang.Integer"&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;generator class="native" /&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;/id&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;property name="name" column="name" type="java.lang.String" /&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;set name="students" lazy="true"&gt; //可不配lazy，因默认是true<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;key column="class_id" /&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;one-to-many class="com.zd.model.Student" /&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;/set&gt;<br /> &nbsp;&nbsp;&nbsp;  &lt;/class&gt;<br /> <br /> &lt;/hibernate-mapping&gt;</p> <p><strong>测试用例：</strong></p> <p>public void testLoad1(){<br /> &nbsp;&nbsp;  Session session = null;<br /> &nbsp;&nbsp;  Transaction ta = null;<br /> &nbsp;&nbsp;  try{<br /> &nbsp;&nbsp;&nbsp;  session = HibernateUtil.getSession();<br /> &nbsp;&nbsp;&nbsp;  ta = session.beginTransaction();<br /> &nbsp;&nbsp;&nbsp;  Classes c = (Classes) session.load(Classes.class, new Integer(2)); //没有sql<br /> &nbsp;&nbsp;&nbsp;  System.out.println("Class.name=" + c.getName());//发出一条sql，但不查 set<br /> &nbsp;&nbsp;&nbsp;  Set stuSet = c.getStudents();//没有发出查询sql，不是统计sql<br /> &nbsp;&nbsp;&nbsp;  //System.out.println(stuSet.size());//发出查询sqlsql<br /> &nbsp;&nbsp;&nbsp;  if(stuSet != null &amp;&amp; !stuSet.isEmpty()){//发出查询sqlsql<br /> &nbsp;&nbsp;&nbsp;&nbsp;  for(Iterator it = stuSet.iterator(); it.hasNext();){<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  Student s = (Student) it.next();//若没有.size(),isEmpty(),就在这边发出sql<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  System.out.println("student.name=" + s.getName());<br /> &nbsp;&nbsp;&nbsp;&nbsp;  }<br /> &nbsp;&nbsp;&nbsp;  }<br /> &nbsp;&nbsp;&nbsp;  ta.commit();<br /> &nbsp;&nbsp;  }catch(Exception e){<br /> &nbsp;&nbsp;&nbsp;  e.printStackTrace();<br /> &nbsp;&nbsp;&nbsp;  if(ta != null){<br /> &nbsp;&nbsp;&nbsp;&nbsp;  ta.rollback();<br /> &nbsp;&nbsp;&nbsp;  }<br /> &nbsp;&nbsp;  }finally{<br /> &nbsp;&nbsp;&nbsp;  //关闭session， user变为detached离线对象<br /> &nbsp;&nbsp;&nbsp;  HibernateUtil.closeSession(session);<br /> &nbsp;&nbsp;  }<br /> &nbsp;&nbsp;<br /> }</p> <p>Hibernate: select classes0_.id as id0_0_, classes0_.name as name0_0_ from classes classes0_ where classes0_.id=?<br /> Class.name=Java Class<br /> Hibernate: select students0_.class_id as  class3_1_, students0_.id as id1_, students0_.id as id1_0_,  students0_.name as name1_0_, students0_.class_id as class3_1_0_ from  student students0_ where students0_.class_id=?<br /> 2<br /> student.name=z3<br /> student.name=l4</p> <p> </p> <p><strong>若&lt;set name="students" lazy="false"&gt; //不延迟加载, 马上加载</strong></p> <p>则在</p> <p>System.out.println("Class.name=" + c.getName());// 就发出2条查询语句了。</p> <p>Hibernate: select classes0_.id as id0_0_, classes0_.name as name0_0_ from classes classes0_ where classes0_.id=?<br /> Hibernate: select students0_.class_id as  class3_1_, students0_.id as id1_, students0_.id as id1_0_,  students0_.name as name1_0_, students0_.class_id as class3_1_0_ from  student students0_ where students0_.class_id=?<br /> Class.name=Java Class<br /> student.name=l4<br /> student.name=z3</p> <p> </p> <p><strong>若&lt;set name="students" lazy="extra"&gt; //和true差不多，只是在写set.size()时，发出selcet count的sql语句，比true好一些。</strong></p> <p><strong>测试用例：</strong></p> <p>public void testLoad1(){<br /> &nbsp;&nbsp;  Session session = null;<br /> &nbsp;&nbsp;  Transaction ta = null;<br /> &nbsp;&nbsp;  try{<br /> &nbsp;&nbsp;&nbsp;  session = HibernateUtil.getSession();<br /> &nbsp;&nbsp;&nbsp;  ta = session.beginTransaction();<br /> &nbsp;&nbsp;&nbsp;  Classes c = (Classes) session.load(Classes.class, new Integer(2));<br /> &nbsp;&nbsp;&nbsp;  System.out.println("Class.name=" + c.getName());<br /> &nbsp;&nbsp;&nbsp;  Set stuSet = c.getStudents();<br /> &nbsp;&nbsp;  System.out.println(stuSet.size());<br /> &nbsp;&nbsp;&nbsp;  if(stuSet != null &amp;&amp; !stuSet.isEmpty()){<br /> &nbsp;&nbsp;&nbsp;&nbsp;  for(Iterator it = stuSet.iterator(); it.hasNext();){<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  Student s = (Student) it.next();<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  System.out.println("student.name=" + s.getName());<br /> &nbsp;&nbsp;&nbsp;&nbsp;  }<br /> &nbsp;&nbsp;&nbsp;  }<br /> &nbsp;&nbsp;&nbsp;  ta.commit();<br /> &nbsp;&nbsp;  }catch(Exception e){<br /> &nbsp;&nbsp;&nbsp;  e.printStackTrace();<br /> &nbsp;&nbsp;&nbsp;  if(ta != null){<br /> &nbsp;&nbsp;&nbsp;&nbsp;  ta.rollback();<br /> &nbsp;&nbsp;&nbsp;  }<br /> &nbsp;&nbsp;  }finally{<br /> &nbsp;&nbsp;&nbsp;  //关闭session， user变为detached离线对象<br /> &nbsp;&nbsp;&nbsp;  HibernateUtil.closeSession(session);<br /> &nbsp;&nbsp;  }<br /> &nbsp;&nbsp;<br /> }</p> <p>Hibernate: select classes0_.id as id0_0_, classes0_.name as name0_0_ from classes classes0_ where classes0_.id=?<br /> Class.name=Java Class<br /> Hibernate: select count(id) from student where class_id =?<br /> 2<br /> Hibernate: select students0_.class_id as class3_1_, students0_.id as  id1_, students0_.id as id1_0_, students0_.name as name1_0_,  students0_.class_id as class3_1_0_ from student students0_ where  students0_.class_id=?<br /> student.name=z3<br /> student.name=l4</p> <p> </p> <p>＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝</p> <p><strong>3.&lt;one-to-one&gt;&lt;many-to-one&gt;单端关联</strong>上，可以取值：false/proxy/no-proxy，默认是proxy(代理），延迟加载作用</p> <p><strong>hbm.xml</strong></p> <p><strong>User.hbm.xml 多的一端</strong></p> <p>&lt;?xml version="1.0" encoding="utf-8"?&gt;<br /> &lt;!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"<br /> "<a href="http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd</a>"&gt;<br /> &lt;hibernate-mapping package="com.model"&gt;<br /> &nbsp;&nbsp;&nbsp;  &lt;class name="User" table="user1" &gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;id name="id" column="user_id" type="java.lang.Integer"&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;generator class="native" /&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;/id&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;property name="name" length="50" type="java.lang.String" /&gt;<br /> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &lt;many-to-one name="group" column="group_id" lazy="proxy"&gt;&lt;/many-to-one&gt; //可不写，默认是proxy<br /> &nbsp;&nbsp;&nbsp;  &lt;/class&gt;<br /> <br /> &lt;/hibernate-mapping&gt;</p> <p>测试用例：</p> <p>public void testGet1(){<br /> &nbsp;&nbsp;  Session session = null;<br /> &nbsp;&nbsp;  Transaction ta = null;<br /> &nbsp;&nbsp;  User user = null;<br /> &nbsp;&nbsp;  try{<br /> &nbsp;&nbsp;&nbsp;  session = HibernateUtil.getSession();<br /> &nbsp;&nbsp;&nbsp;  ta = session.beginTransaction();<br /> &nbsp;&nbsp;&nbsp;  user = (User)session.load(User.class, new Integer(3)); //无sql<br /> &nbsp;&nbsp;&nbsp;  System.out.println("user.name=" + user.getName()); //有一条sql<br /> &nbsp;&nbsp;&nbsp;  Group group = user.getGroup();//无sql<br /> &nbsp;&nbsp;&nbsp;  System.out.println("group.name=" + group.getName());//有一条sql<br /> &nbsp;&nbsp;&nbsp;  ta.commit();<br /> &nbsp;&nbsp;  }catch(Exception e){<br /> &nbsp;&nbsp;&nbsp;  e.printStackTrace();<br /> &nbsp;&nbsp;&nbsp;  ta.rollback();<br /> &nbsp;&nbsp;  }finally{<br /> &nbsp;&nbsp;&nbsp;  //关闭session， user变为detached离线对象<br /> &nbsp;&nbsp;&nbsp;  HibernateUtil.closeSession(session);<br /> &nbsp;&nbsp;  }<br /> &nbsp;&nbsp;<br /> }</p> <p>若&lt;many-to-one name="group" column="group_id"<strong><em> lazy="false</em></strong>"&gt;&lt;/many-to-one&gt;</p> <p>不延迟加载，立即加载，</p> <p>System.out.println("user.name=" + user.getName()); //发出2条sql语句</p> <p> </p> <p>==========================================</p> <p>hibernate 中的 lazy="proxy" 和 <strong>lazy="no-proxy"</strong> 到底是什么意思?</p> <p>举个例子吧：   <br />   Child   &lt;-   many-to-one   -&gt;Parent   <br />     <br />   class   Child   {   <br />       private   Parent   parent;   <br />     <br />       public   Parent   getParent   (){   <br />           return   this.parent;//访问了实例变量   <br />       }   <br />         <br />   }   <br />     <br />   class   Parent   {   <br />       private   String   name;   <br />     <br />       public   String   getName(){   <br />           return   this.name;//访问了实例变量   <br />       }   <br />     <br />       public   void   f(){   <br />           System.out.println("invokeing   f()");//没有访问实例变量   <br />       }   <br />   }   <br />     <br />   如果   <strong>many-to-one     的lazy设为proxy,当child.getParent().getName()或child.getParent().f()时，parent都 会被抓取，若设为no-proxy,调用child.getParent().f()时，parent是不会被抓取的，同时这种方式需要编译时字节码增强，否则和proxy没区别。 (注：测试发现真和proxy一样，不能理解  编译时字节码增强，要再哪修改，或是什么条件？）</strong></p> <p> </p> <p>如 果设置了   lazy="proxy"，就&nbsp;&nbsp;  ，当通过   child   来调用其关联的   parent，   如果调用    parent   类中定义的任何方法,都会抓取   parent   (所谓的抓取是不是就是从数据库查询,执行一次   select   ?)      <br />   如果设置了   lazy="no-proxy"   ,只有调用   parent   类中牵涉到类变量的方法,才会抓取   parent,否则,就像调用   f(),   不会抓取   parent&nbsp;&nbsp;  </p> <p>."编译时字节码增强"   是什么意思?   <br />   "字节码增强"分编译期和运行期2种，编译期是修改java类编译后的class字节码文件，在上面附加&#8220;增强&#8221;操作。（不明白why？）</p> <p> </p> <p>＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝＝</p> lazy  (可选 - 默认为 proxy):  默认情况下，单点关联是经过代理的。lazy="no-proxy"指定此属性应该在实例变量第一次被访问时应该延迟抓取（fetche  lazily）（需要运行时字节码的增强）。 lazy="false"指定此关联总是被预先抓取。注意，如果constrained="false",  不可能使用代理，Hibernate会采取预先抓取！ </div><img src ="http://www.blogjava.net/lzn1446/aggbug/354970.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lzn1446/" target="_blank">blue_leo</a> 2011-07-25 11:42 <a href="http://www.blogjava.net/lzn1446/articles/354970.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转】Hibernate 原汁原味的四种抓取策略</title><link>http://www.blogjava.net/lzn1446/articles/339558.html</link><dc:creator>blue_leo</dc:creator><author>blue_leo</author><pubDate>Wed, 01 Dec 2010 16:05:00 GMT</pubDate><guid>http://www.blogjava.net/lzn1446/articles/339558.html</guid><wfw:comment>http://www.blogjava.net/lzn1446/comments/339558.html</wfw:comment><comments>http://www.blogjava.net/lzn1446/articles/339558.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lzn1446/comments/commentRss/339558.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lzn1446/services/trackbacks/339558.html</trackback:ping><description><![CDATA[<h4> 最近在研究 Hibernate 的性能优化的时候碰到了"抓取策略", 由于以前没有详细的研究过,</h4>
<p>&nbsp;&nbsp;&nbsp;
所以到处找资料, 但是无论从一些讲 Hibernate 书籍,还是他人 Blog 中都没有找到详细</p>
<p>&nbsp;&nbsp;&nbsp; 介绍
Hibernate 文档中所说的原汁原味的抓取策略, 综合懒加载等等特性混在了一起, 所</p>
<p>&nbsp;&nbsp;&nbsp;
以在这自己在借鉴了他人的基础上研究了下原汁原味的 Hibernate 四种"抓取策略";</p>
<ul>
    <li><em><strong>连
    接抓取（Join fetching）</strong></em> - Hibernate通过 在<code>SELECT</code>语句使用<code>OUTER
    JOIN       <br />
    </code>（外连接）来 获得对象的关联实例或者关联集合.      <hr />
    </li>
    <li><em><strong>查
    询抓取（Select fetching）</strong></em> - 另外发送一条 <code>SELECT</code>
    语句抓取当前对象的关联实      <br />
    体或集合。除非你显式的指定<code>lazy="false"</code>禁止 延迟抓取（lazy
    fetching），否      <br />
    则只有当你真正访问关联关系的时候，才会执行第二条select语句.      <hr />
    </li>
    <li><em><strong>子查询抓取（Subselect fetching）</strong></em> - 另外发送一条<code>SELECT</code>
    语句抓取在前面查询到      <br />
    （或者抓取到）的所有实体对象的关联集合。除非你显式的指定<code>lazy="false"</code>
    禁止延迟      <br />
    抓取（lazy fetching），否则只有当你真正访问关联关系的时候，才会执行第二条      <br />
    select
    语句      <hr />
    </li>
    <li><em><strong>批量抓取（Batch fetching）</strong></em> -
    对查询抓取的优化方案， 通过指定一个主键或外键      <br />
    列表，Hibernate使用单条<code>SELECT</code>语句获
    取一批对象实例或集合</li>
</ul>
<p>&nbsp;&nbsp;&nbsp; 这是文档中的四种抓取策略, 我用 Customer 与 Order
的一个双向一对多例子来使用四种</p>
<p>&nbsp;&nbsp;&nbsp; 抓取策略看看他们的不同之处;</p>
<p><em>&nbsp;&nbsp;&nbsp; Customer :</em></p>
<ol>
    <li>public class Customer {&nbsp; </li>
    <li>private long
    id;&nbsp; </li>
    <li>private String name;&nbsp; </li>
    <li>private
    Set&lt;Order&gt; orders;&nbsp; </li>
    <li>// getter/setter 略</li>
    <li>}&nbsp;
    </li>
</ol>
<p><em>&nbsp;&nbsp;&nbsp; Order :</em></p>
<ol>
    <li>public class Order {&nbsp; </li>
    <li>private long id;&nbsp; </li>
    <li>private String name;&nbsp; </li>
    <li>private Customer
    customer;&nbsp; </li>
    <li>// getter/setter略</li>
    <li>}&nbsp; </li>
</ol>
<p><em>Order 的映射文件是不变的, 放在这 :</em></p>
<ol>
    <li>&lt;hibernate-mapping
    package="com.purking.strategys.endUpOne"&gt;</li>
    <li>&lt;class
    name="Order" table="Order_Table"&gt;</li>
    <li>&lt;id name="id"&gt;</li>
    <li>&lt;generator class="native" /&gt;</li>
    <li>&lt;/id&gt;</li>
    <li>&lt;property name="name" length="20" column="Order_Name" /&gt;</li>
    <li>&lt;many-to-one name="customer"</li>
    <li>class="Customer"</li>
    <li>lazy="proxy"</li>
    <li>fetch="select"</li>
    <li>column="Cus_ID"</li>
    <li>cascade="save-update" /&gt;</li>
    <li>&lt;/class&gt;</li>
    <li>&lt;/hibernate-mapping&gt;</li>
</ol>
<h4><strong><em>连
接抓取（Join fetching）</em></strong></h4>
<p>&nbsp;&nbsp;&nbsp; 连接抓取, 使用连接抓取可以将原本需要查询两次(或多次)表的多次查询 整合到只需</p>
<p>要一次查询即可完成,
举个例子, 我们在初始化一个含有一对多关系的 Customer 与</p>
<p>Order 的时候, 会先查询 Customer
表,找到需要的 Customer , 然后再根据</p>
<p>Customer.id 到 Order 表中查询将Order 集合初始化,
那么在此完成初始化则需要</p>
<p>发送至少两条 SQL 语句, 而如果使用 join 查询的话, 其会根据需要查询的</p>
<p>Customer.id,
将 Customer 表与 Order 表连接起来进行查询,仅仅一条 SQL 语</p>
<p>句就可以将需要的数据全部查询回来;</p>
<p>使用连接抓取的配置文件 :</p>
<ol>
    <li>&lt;hibernate-mapping
    package="com.purking.strategys.endUpOne"&gt;</li>
    <li>&lt;class
    name="Customer" table="Customer_Table" lazy="true"&gt;</li>
    <li>&lt;id
    name="id"&gt;</li>
    <li>&lt;generator class="native" /&gt;</li>
    <li>&lt;/id&gt;</li>
    <li>&lt;property name="name" length="20" column="Cus_Name" /&gt;</li>
    <li>&lt;set name="orders"</li>
    <li>inverse="true"</li>
    <li>fetch="join"&nbsp;
    //---- Here&nbsp; </li>
    <li>&lt;!-- 这里关闭懒加载是为了试验明显 --&gt;</li>
    <li>lazy="false"&gt;</li>
    <li>&lt;key column="Cus_ID" /&gt;</li>
    <li>&lt;one-to-many
    class="Order" /&gt;</li>
    <li>&lt;/set&gt;</li>
    <li>&lt;/class&gt;</li>
    <li>&lt;/hibernate-mapping&gt;</li>
</ol>
<p>我们使用如此查询语句 :</p>
<ol>
    <li>Customer c1 = (Customer)session.get(Customer.class, 11l);&nbsp; </li>
    <li>c1.getOrders().size();&nbsp; </li>
</ol>
<p>Hibernate 发出的 SQL 语句为 : </p>
<ol>
    <li>select&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; customer0_.id as id0_1_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; customer0_.Cus_Name as Cus2_0_1_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;
    orders1_.Cus_ID as Cus3_3_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; orders1_.id as id3_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; orders1_.id as id1_0_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; orders1_.Order_Name
    as Order2_1_0_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; orders1_.Cus_ID as Cus3_1_0_&nbsp;&nbsp; </li>
    <li>from&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; Customer_Table customer0_&nbsp;&nbsp; </li>
    <li>left
    outer join&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; Order_Table orders1_&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    on customer0_.id=orders1_.Cus_ID&nbsp;&nbsp; </li>
    <li>where&nbsp; </li>
    <li>customer0_.id=?&nbsp;
    </li>
</ol>
<p>在此, Hibernate 使用了 left outer join 连接两个表以一条 SQL 语句将
Order 集合</p>
<p>给初始化了;</p>
<h4>   <br />
<strong><em>查询抓取（Select
fetching）</em></strong></h4>
<p><strong>&nbsp;&nbsp;&nbsp; 查询抓取, 这种策略是在集合抓取的时候的默认策略,
即如果集合需要初始化, 那么</strong></p>
<p><strong>会重新发出一条 SQL 语句进行查询; 这是集合默认的抓取策略,
也就是我们常会出现</strong></p>
<p><strong>N+1次查询的查询策略;</strong></p>
<p><strong>配
置文件 :</strong></p>
<ol>
    <li>&lt;hibernate-mapping
    package="com.purking.strategys.endUpOne"&gt;</li>
    <li>&lt;class
    name="Customer" table="Customer_Table" lazy="true"&gt;</li>
    <li>&lt;id
    name="id"&gt;</li>
    <li>&lt;generator class="native" /&gt;</li>
    <li>&lt;/id&gt;</li>
    <li>&lt;property name="name" length="20"
    column="Cus_Name" /&gt;</li>
    <li>&lt;set name="orders"</li>
    <li>inverse="true"</li>
    <li>fetch="select"&gt;</li>
    <li>&lt;key column="Cus_ID" /&gt;</li>
    <li>&lt;one-to-many class="Order" /&gt;</li>
    <li>&lt;/set&gt;</li>
    <li>&lt;/class&gt;</li>
    <li>&lt;/hibernate-mapping&gt;</li>
</ol>
<p> 查询语句不变, 看看 Hibernate 发出的 SQL 语句:</p>
<ol>
    <li>Hibernate:&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; select&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    customer0_.id as id0_0_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; customer0_.Cus_Name as
    Cus2_0_0_&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; from&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    Customer_Table customer0_&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; where&nbsp; </li>
    <li>customer0_.id=?&nbsp;
    </li>
    <li>Hibernate:&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; select&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    orders0_.Cus_ID as Cus3_1_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orders0_.id as
    id1_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orders0_.id as id1_0_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    orders0_.Order_Name as Order2_1_0_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    orders0_.Cus_ID as Cus3_1_0_&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; from&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    Order_Table orders0_&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; where&nbsp; </li>
    <li>orders0_.Cus_ID=?&nbsp;
    </li>
</ol>
<p><strong>这就是, 重新发出一条 SQL 语句, 初始化了 Orders
集合;</strong></p>
<h4><em>子查询抓取（Subselect fetching）</em><em>     <br />
</em></h4>
<p>&nbsp;&nbsp;&nbsp; 子查询抓取, 另外发送一条SELECT 语句抓取在前面查询到（或者抓取到）的所有实</p>
<p>体对象的关联集合.
这个理解起来有点糊涂, 举个例子 : 如果你使用 Query 查询出了</p>
<p>4 个 Customer 实体,
由于开启了懒加载,那么他们的 Orders 都没有被初始化, 那么我</p>
<p>现在手动初始化一个Customer 的 Orders
,此时由于我选的是 Subselect fetching</p>
<p>策略,所以 Hibernate 会将前面查询到的实体对象(4 个
Customer)的关联集合(在 </p>
<p>&lt;set name="orders" fetch="subselect" /&gt;
)使用一条 Select 语句一次性抓取</p>
<p>回来, 这样减少了与数据库的交互次数, 一次将每个对象的集合都给初始化了;</p>
<p>[他
是如何这么智能的呢? 原来,他是将上一次查询的 SQL 语句作为这一次查询的 SQL</p>
<p>语句的 where 子查询,
所以上次查询到几个对象,那么这次就初始化几个对象的集</p>
<p>合----- 正因为如此, 所以 subselect 只在
&lt;set&gt; 集合中出现 ];</p>
<p>配置文件: </p>
<ol>
    <li>&lt;hibernate-mapping
    package="com.purking.strategys.endUpOne"&gt;</li>
    <li>&lt;class
    name="Customer" table="Customer_Table" lazy="true"&gt;</li>
    <li>&lt;id
    name="id"&gt;</li>
    <li>&lt;generator class="native" /&gt;</li>
    <li>&lt;/id&gt;</li>
    <li>&lt;property name="name" length="20" column="Cus_Name" /&gt;</li>
    <li>&lt;set name="orders"</li>
    <li>inverse="true"</li>
    <li>fetch="subselect"</li>
    <li>lazy="true"&gt;</li>
    <li>&lt;key column="Cus_ID" /&gt;</li>
    <li>&lt;one-to-many class="Order" /&gt;</li>
    <li>&lt;/set&gt;</li>
    <li>&lt;/class&gt;</li>
    <li>&lt;/hibernate-mapping&gt;</li>
</ol>
<p>测试的语句有变化 :</p>
<ol>
    <li>List results = session&nbsp; </li>
    <li>.createQuery("From
    Customer c where c.id in (11,14,17,20)")&nbsp; </li>
    <li>.list();&nbsp; </li>
    <li>// 这里的四个 id 是我数据库中已经准备好的数据</li>
    <li>Customer c0 =
    (Customer)results.get(0);&nbsp; </li>
    <li>c0.getOrders().size();&nbsp; </li>
</ol>
<p>这个时候再来看看 Hibernate 发出了什么样的 SQL 语句 :</p>
<ol>
    <li>Hibernate:&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; select&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    customer0_.id as id0_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; customer0_.Cus_Name as
    Cus2_0_&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; from&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Customer_Table
    customer0_&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; where&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; customer0_.id
    in (&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 11 , 14 , 17 , 20&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    )&nbsp; </li>
    <li>Hibernate:&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; select&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    orders0_.Cus_ID as Cus3_1_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orders0_.id as id1_,&nbsp;
    </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orders0_.id as id1_0_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    orders0_.Order_Name as Order2_1_0_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    orders0_.Cus_ID as Cus3_1_0_&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; from&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    Order_Table orders0_&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; where&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    orders0_.Cus_ID in (&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; select&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    customer0_.id&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    Customer_Table customer0_&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; where&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    customer0_.id in (&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 11 , 14 , 17 , 20&nbsp;
    </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; )&nbsp; </li>
</ol>
<p>是
不是发出的 SQL 语句形式与这个抓取策略的名字一样? Hibernate 的命名很清晰的;</p>
<h4><em>批量抓取（Batch
fetching）</em></h4>
<p>批量抓取:"对查询抓取的
优化方案,通过指定一个主键或外键列表，Hibernate使用</p>
<p>单条SELECT语句获取一批对象实例或集合", 也就是说其本质与
select fetching 是</p>
<p>一样的,只不过将一次一条的 select 策略改为一次 N 条的批量 select 查询;
举个例</p>
<p>子 : 还是借用 Subselect fetching 的例子,我查询出了 4 个 Customer 实体,</p>
<p>Orders
开启了懒加载, 所以我现在来手动初始化一个 Customer 的 orders 属性,</p>
<p>这种策略本质上就是 select
fetching,所以如此设置 :</p>
<p>&lt;set name="orders" fetch="select"
batch-size="3" /&gt; 那么此时我初始化</p>
<p>一个 Customer 的 orders 集合的时候,
Hibernate 还是发出了一条 SQL 语句,</p>
<p>不过这条 SQL 与是通过指定了 Order 表中的 Customer_ID
外键列表(2个), 这个</p>
<p>时候 Hibernate 会以一条 SQL 语句初始化 batch-size 指定的数量的
orders 集合;</p>
<p>[他是如何做到的呢? 通过一个主键或外键 列表 做到的, 他将 4 个 Customer 根据</p>
<p>batch-size
分成了两组, 一组有三个 Customer id 值的列表,第二组只有一个,</p>
<p>在初始化 orders
集合的时候就是根据这两个列表来初始化的]</p>
<p>配置文件 :</p>
<ol>
    <li>&lt;hibernate-mapping
    package="com.purking.strategys.endUpOne"&gt;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; &lt;class
    name="Customer" table="Customer_Table" lazy="true"&gt;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    &lt;id name="id"&gt;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;generator
    class="native" /&gt;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/id&gt;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    &lt;property name="name" length="20" column="Cus_Name" /&gt;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    &lt;set name="orders"</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; inverse="true"</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    fetch="select"</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lazy="true"</li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    batch-size="3"&gt;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;key column="Cus_ID"
    /&gt;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;one-to-many class="Order" /&gt;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/set&gt;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; &lt;/class&gt;&nbsp; </li>
    <li>&lt;/hibernate-mapping&gt;&nbsp;
    </li>
</ol>
<p>在此,我关闭了集合默认的懒加载, 更有利于试验结果测试代码不变,</p>
<p>再来看看 Hibernate
发出的 SQL 语句 :</p>
<ol>
    <li>Hibernate:&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; select&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    customer0_.id as id0_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; customer0_.Cus_Name as
    Cus2_0_&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; from&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Customer_Table
    customer0_&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; where&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; customer0_.id
    in (&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 11 , 14 , 17 , 20&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    )&nbsp; </li>
    <li>Hibernate:&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; select&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    orders0_.Cus_ID as Cus3_1_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orders0_.id as id1_,&nbsp;
    </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orders0_.id as id1_0_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    orders0_.Order_Name as Order2_1_0_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    orders0_.Cus_ID as Cus3_1_0_&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; from&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    Order_Table orders0_&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; where&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    orders0_.Cus_ID in (&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ?, ?, ?&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    )&nbsp; </li>
    <li>Hibernate:&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; select&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    orders0_.Cus_ID as Cus3_1_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orders0_.id as id1_,&nbsp;
    </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orders0_.id as id1_0_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    orders0_.Order_Name as Order2_1_0_,&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    orders0_.Cus_ID as Cus3_1_0_&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; from&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
    Order_Table orders0_&nbsp;&nbsp; </li>
    <li>&nbsp;&nbsp;&nbsp; where&nbsp; </li>
    <li>orders0_.Cus_ID=?&nbsp;
    </li>
</ol>
<p>原本需要四次 Select 的查询, 由于 Batch-size=3 只用了两次</p>
<p>就完成了;</p>
<hr />
<h5>总结: </h5>
<p>&nbsp;&nbsp;&nbsp; 好了, 这里的四种抓取策略说明完了, 来全局看一下, 通过例子可以看出, 这四种抓取</p>
<p>策略并不是所有的情况都合适的, 例如, 如果我需要初始化的是一个单独的实体, 那</p>
<p>么 subselect
对其就没有效果,因为其本身就只需要查询一个对象, 所以 : </p>
<ol>
    <li>Join fetching , Select
    fetching 与 Batch-size 可以为单个实体的抓取进     <br />
    行性能优化; </li>
    <li>Join
    fetching , Select fetching ,Subselect fetching , Batch fetching     <br />
    都
    可以为集合的抓取进行性能优化;</li>
</ol>
<p>注: 这里对于单个实体可以使用 Batch-size 可能会有点疑惑, 其实在
&lt;class &gt; 上是</p>
<p>具有 Batch-size 抓取策略的; 试想, 使用一个如果是一对一关系呢? 例如
Customer </p>
<p>与 IdCard, 利用 HQL 查询出 4 个 Customer , 我们想一次性初始化 4 个
Customer </p>
<p>的 IdCard 怎么办, 设置 &lt;class name="IdCard"
batch-size="4" &gt; , 可能我们</p>
<p>想设置的地方是 &lt;one-to-one batch-size&gt;
但是这里没有提供这个属性, 可能是因为</p>
<p>如果设置了不好理解吧..</p>
<img src ="http://www.blogjava.net/lzn1446/aggbug/339558.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lzn1446/" target="_blank">blue_leo</a> 2010-12-02 00:05 <a href="http://www.blogjava.net/lzn1446/articles/339558.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转】hibernate中unsaved_value的作用 </title><link>http://www.blogjava.net/lzn1446/articles/307124.html</link><dc:creator>blue_leo</dc:creator><author>blue_leo</author><pubDate>Thu, 24 Dec 2009 04:02:00 GMT</pubDate><guid>http://www.blogjava.net/lzn1446/articles/307124.html</guid><wfw:comment>http://www.blogjava.net/lzn1446/comments/307124.html</wfw:comment><comments>http://www.blogjava.net/lzn1446/articles/307124.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lzn1446/comments/commentRss/307124.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lzn1446/services/trackbacks/307124.html</trackback:ping><description><![CDATA[<p>当你显式的使用session.save()或者session.update()操作一个对象的时候，实际上是用不到unsaved-value
的。某些情况下(父子表关联保存)，当你在程序中并没有显式的使用save或者update一个持久对象，那么Hibernate需要判断被操作的对象究
竟是一个已经持久化过的持久对象，是一个尚未被持久化过的内存临时对象。例如：</p>
<div class="code_title">代码</div>
<div class="code_div">
<div class="dp-highlighter">
<ol class="dp-j">
    <li class="alt"><span><span>Session&nbsp;session&nbsp;=&nbsp;...; &nbsp;&nbsp;</span></span></li>
    <li class=""><span>Transaction&nbsp;tx&nbsp;=&nbsp;...; &nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>Parent&nbsp;parent&nbsp;=&nbsp;(Parent)&nbsp;session.load(Parent.</span><span class="keyword">class</span><span>,&nbsp;id); &nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>Child&nbsp;child&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Child(); &nbsp;&nbsp;</span></li>
    <li class="alt"><span>child.setParent(parent); &nbsp;&nbsp;</span></li>
    <li class=""><span>child.setName(</span><span class="string">"sun"</span><span>); &nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>parent.addChild(child); &nbsp;&nbsp;</span></li>
    <li class="alt"><span>s.update(parent); &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>s.flush(); &nbsp;&nbsp;</span></li>
    <li class=""><span>tx.commit(); &nbsp;&nbsp;</span></li>
    <li class="alt"><span>s.close();&nbsp;&nbsp;</span></li>
</ol>
</div>
</div>
<script type="text/javascript">render_code();</script>
<p>在上例中，程序并没有显式的session.save(child);
那么Hibernate需要知道child究竟是一个临时对象，还是已经在数据库中有的持久对象。如果child是一个新创建的临时对象(本例中就是这种
情况)，那么Hibernate应该自动产生session.save(child)这样的操作，如果child是已经在数据库中有的持久对象，那么
Hibernate应该自动产生session.update(child)这样的操作。</p>
<p>因此我们需要暗示一下Hibernate，究竟child对象应该对它自动save还是update。在上例中，显然我们应该暗示
Hibernate对child自动save，而不是自动update。那么Hibernate如何判断究竟对child是save还是update呢？
它会取一下child的主键属性 child.getId() ，这里假设id是
java.lang.Integer类型的。如果取到的Id值和hbm映射文件中指定的unsave-value相等，那么Hibernate认为
child是新的内存临时对象，发送save，如果不相等，那么Hibernate认为child是已经持久过的对象，发送update。</p>
<p>unsaved-value="null" (默认情况，适用于大多数对象类型主键 Integer/Long/String/...)</p>
<p>当Hibernate取一下child的Id，取出来的是null(在上例中肯定取出来的是null)，和unsaved-value设定值相等，发送save(child)</p>
<p>当Hibernate取一下child的id，取出来的不是null，那么和unsaved-value设定值不相等，发送update(child)</p>
<p>例如下面的情况：</p>
<div class="code_title">代码</div>
<div class="code_div">
<div class="dp-highlighter">
<ol class="dp-j">
    <li class="alt"><span><span>Session&nbsp;session&nbsp;=&nbsp;...; &nbsp;&nbsp;</span></span></li>
    <li class=""><span>Transaction&nbsp;tx&nbsp;=&nbsp;...; &nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>Parent&nbsp;parent&nbsp;=&nbsp;(Parent)&nbsp;session.load(Parent.</span><span class="keyword">class</span><span>,&nbsp;id); &nbsp;&nbsp;</span></li>
    <li class="alt"><span>Child&nbsp;child&nbsp;=&nbsp;(Child)&nbsp;session.load(Child.</span><span class="keyword">class</span><span>,&nbsp;childId); &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>child.setParent(parent); &nbsp;&nbsp;</span></li>
    <li class=""><span>child.setName(</span><span class="string">"sun"</span><span>); &nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span></li>
    <li class=""><span>parent.addChild(child); &nbsp;&nbsp;</span></li>
    <li class="alt"><span>s.update(parent); &nbsp;&nbsp;</span></li>
    <li class=""><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>s.flush(); &nbsp;&nbsp;</span></li>
    <li class=""><span>tx.commit(); &nbsp;&nbsp;</span></li>
    <li class="alt"><span>s.close();&nbsp;&nbsp;</span></li>
</ol>
</div>
</div>
<script type="text/javascript">render_code();</script>
<p>child已经在数据库中有了，是一个持久化的对象，不是新创建的，因此我们希望Hibernate发送update(child)，在该例
中，Hibernate取一下child.getId()，和unsave-value指定的null比对一下，发现不相等，那么发送
update(child)。</p>
<p>BTW:
parent对象不需要操心，因为程序显式的对parent有load操作和update的操作，不需要Hibernate自己来判断究竟是save还是
update了。我们要注意的只是child对象的操作。另外unsaved-value是定义在Child类的主键属性中的。</p>
<div class="code_title">代码</div>
<div class="code_div">
<div class="dp-highlighter">
<ol class="dp-xml">
    <li class="alt"><span><span class="tag">&lt;</span><span class="tag-name">class</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">"Child"</span><span>&nbsp;</span><span class="attribute">table</span><span>=</span><span class="attribute-value">"child"</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></span></li>
    <li class=""><span class="tag">&lt;</span><span class="tag-name">id</span><span>&nbsp;</span><span class="attribute">column</span><span>=</span><span class="attribute-value">"id"</span><span>&nbsp;</span><span class="attribute">name</span><span>=</span><span class="attribute-value">"id"</span><span>&nbsp;</span><span class="attribute">type</span><span>=</span><span class="attribute-value">"integer"</span><span>&nbsp;</span><span class="attribute">unsaved-value</span><span>=</span><span class="attribute-value">"null"</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>&nbsp;&nbsp;</span><span class="tag">&lt;</span><span class="tag-name">generator</span><span>&nbsp;</span><span class="attribute">class</span><span>=</span><span class="attribute-value">"identity"</span><span class="tag">/&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class=""><span class="tag">&lt;/</span><span class="tag-name">id</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
    <li class="alt"><span>... &nbsp;&nbsp;</span></li>
    <li class=""><span class="tag">&lt;/</span><span class="tag-name">class</span><span class="tag">&gt;</span><span>&nbsp;&nbsp;</span></li>
</ol>
</div>
</div>
<script type="text/javascript">render_code();</script>
<p>如果主键属性不是对象型，而是基本类型，如int/long/double/...，那么你需要指定一个数值型的unsaved-value，例如：</p>
<div class="code_title">代码</div>
<div class="code_div">
<div class="dp-highlighter">
<ol class="dp-j">
    <li class="alt"><span><span>unsaved-</span><span class="keyword">null</span><span>=</span><span class="string">"0"</span><span>&nbsp;&nbsp;</span></span></li>
</ol>
</div>
</div>
<script type="text/javascript">render_code();</script>
<p>在此提醒大家，很多人以为对主键属性定义为int/long，比定义为Integer/Long运行效率来得高，认为基本类型不需要进行对象的封装
和解构操作，因此喜欢把主键定义为int/long的。但实际上，Hibernate内部总是把主键转换为对象型进行操作的，就算你定义为int
/long型的，Hibernate内部也要进行一次对象构造操作，返回给你的时候，还要进行解构操作，效率可能反而低也说不定。因此大家一定要扭转一个
观点，在Hibernate中，主键属性定义为基本类型，并不能够比定义为对象型效率来的高，而且也多了很多麻烦，因此建议大家使用对象型的
Integer/Long定义主键。</p>
<p>unsaved-value="none"和 <br />
unsaved-value="any"</p>
<p>主主要用在主键属性不是通过Hibernate生成，而是程序自己setId()的时候。</p>
<p>在这里多说一句，强烈建议使用Hibernate的id generator，或者你可以自己扩展Hibernate的id
generator，特别注意不要使用有实际含义的字段当做主键来用！例如用户类User，很多人喜欢用用户登陆名称做为主键，这是一个很不好的习惯，当
用户类和其他实体类有关联关系的时候，万一你需要修改用户登陆名称，一改就需要改好几张表中的数据。偶合性太高，而如果你使用无业务意义的id
generator，那么修改用户名称，就只修改user表就行了。</p>
<p>由这个问题引申出来，如果你严格按照这个原则来设计数据库，那么你基本上是用不到手工来setId()的，你用Hibernate的id generator就OK了。因此你也不需要了解当</p>
<p>unsaved-value="none"和 <br />
unsaved-value="any"</p>
<p>究竟有什么含义了。如果你非要用assigned不可，那么继续解释一下：</p>
<p>unsaved-value="none" 的时候，由于不论主键属性为任何值，都不可能为none，因此Hibernate总是对child对象发送update(child)</p>
<p>unsaved-value="any" 的时候，由于不论主键属性为任何值，都肯定为any，因此Hibernate总是对child对象发送save(child)</p>
<p>大多数情况下，你可以避免使用assigned，只有当你使用复合主键的时候不得不手工setId()，这时候需要你自己考虑究竟怎么设置unsaved-value了，根据你自己的需要来定。</p>
<p>BTW: Gavin King强烈不建议使用composite-id，强烈建议使用UserType。</p>
<p>因此，如果你在系统设计的时候，遵循如下原则：</p>
<p><span style="color: red;">1、使用Hibernate的id generator来生成无业务意义的主键，不使用有业务含义的字段做主键，不使用assigned。</span></p>
<p>2、使用对象类型(String/Integer/Long/...)来做主键，而不使用基础类型(int/long/...)做主键</p>
<p>3、不使用composite-id来处理复合主键的情况，而使用UserType来处理该种情况。</p>
<p>那么你永远用的是unsaved-value="null" ，不可能用到any/none/..了。</p>
<img src ="http://www.blogjava.net/lzn1446/aggbug/307124.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lzn1446/" target="_blank">blue_leo</a> 2009-12-24 12:02 <a href="http://www.blogjava.net/lzn1446/articles/307124.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转】hibernate集合映射inverse和cascade </title><link>http://www.blogjava.net/lzn1446/articles/307122.html</link><dc:creator>blue_leo</dc:creator><author>blue_leo</author><pubDate>Thu, 24 Dec 2009 03:56:00 GMT</pubDate><guid>http://www.blogjava.net/lzn1446/articles/307122.html</guid><wfw:comment>http://www.blogjava.net/lzn1446/comments/307122.html</wfw:comment><comments>http://www.blogjava.net/lzn1446/articles/307122.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/lzn1446/comments/commentRss/307122.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/lzn1446/services/trackbacks/307122.html</trackback:ping><description><![CDATA[<font size="2">4. hibernate如何根据pojo来更新数据库<br />
<br />
4.0 在commit/flush之前，hibernate不会对pojo对象作神秘的处理。<br />
4.0.1 在select查询出pojo时，hibernate根据&#8220;字段--属性&#8221;的对应关系，用字段的值填充pojo的属性；<br />
然后根据&#8220;关系标记&#8221;生成sql语句从relationTable中查询出满足条件的relationPojo，并把这些relatinPojo<br />
放到&#8220;关系属性&#8221;中。这个过程是机械的。<br />
<br />
4.0.2 在pojo对象被查出来后，到commit(或flush)之前，它将是一个普通的java对象，hibernate不会做额外的手脚。<br />
比如，不会限制你设置一个属性的值为null或其它任何值<br />
在集合类Set的add(object)操作时， 不会改变object的值，不会检查参数object是否是一个pojo对象<br />
设置mainPojo的一个&#8220;桥属性&#8221;的值，不会自动设置relationPojo的对应的&#8220;桥属性&#8221;的值。<br />
执行session.delete(pojo)时，pojo本身没有变化，他的属性值也没有变化。<br />
执行session.save(pojo)时，如果pojo的id不是hibernate或数据库生成,则它的值没有变化。<br />
如果pojo的id是hibernate或数据库生成，则hibernate会把id给pojo设上去。<br />
<br />
extend: 对lazy=true的set，hibernate在进行set的操作(调用java.util.Set中声明的方法)时<br />
会先inialize这个set，仅此而已。而inialize仅仅是从数据库中捞出set的数据。 <br />
如果一个set已经被inialize了，那么对它进行的操作就是java.util.Set接口中定义的语义。<br />
<br />
另外，如果id由hibernate来生成，那么在save(pojo)时，hibernate会改变该pojo，会设置它的id，这<br />
可能改变该pojo的hashCode，详细地讨论见帖《》<br />
<br />
mapping文件中标记的某些属性及pojo对象的操作会对数据库操作产生影响，这些影响都是在commit时才会起作用。<br />
而在commit前pojo的状态不受它们的影响。<br />
<br />
不过，待commit之时，将由hibernate完全掌控，它好像知道pojo对象从创建到commit这中间的所有变化。<br />
<br />
<br />
4.01. 关联更新<br />
"关系标记"对应的属性是一个pojo或一个pojo的集合，修改&#8220;关系属性&#8221;的值能会导致更新mainTable表，也可能会更新relationTable表。<br />
<br />
这种更新暂叫&#8220;关联更新&#8221;。<br />
<br />
<br />
4.1.inverse属性的作用（假定没有设置cascade属性） <br />
4.1.1 &#8220;只有集合标记（set/map/list/array/bag）才有inverse属性&#8221;。<br />
————不妨以标记set为例，具体为&#8220;一个地区（Address表）的学校（School表）&#8221; -- address.schoolSet。<br />
<br />
4.1.2 &#8220;set的inverse属性决定是否把对set的改动反映到数据库中去。<br />
inverse=false————反映；inverse=true————不反映&#8221;<br />
inverse属性默认为false<br />
<br />
对&lt;one-to-many&gt;和&lt;many-to-many&gt;子标记，这两条都适用。<br />
不管是对set做什么操作，4.1.2都适用。<br />
<br />
4.1.3当inverse=false时，hibernate如何将对set的改动反映到数据库中：<br />
<br />
对set的操作主要有：（1）新增元素 address.getSchoolSet().add(oneSchool);<br />
（2）删除元素 address.getSchoolSet().remove(oneSchool);<br />
（3）删除set address.setSchoolSet(null);<br />
（4）设新set address.setSchoolSet( newSchoolSet);<br />
（5）转移set otherSchoolSet = otherAddress.getSchoolSet();<br />
otherAddress.setSchoolSet(null);<br />
address.setSchoolSet(otherSchoolSet);<br />
（6）改变set中元素的属性的值 如果是改变key属性，这会导致异常<br />
如果改变的是普通的属性，则hibernate认为set没有变化（在后面可以看出缘由）。<br />
所以这种情形不予考虑。<br />
<br />
改变set后，hibernate对数据库的操作根据是&lt;one-to-many&gt;关系还是&lt;many-to-many&gt;关系而有不同。<br />
<br />
对one-to-many，对school set的改动，会改变表SCHOOL中的数据:<br />
#SCHOOL_ID是school表的主键，SCHOOL_ADDRESS是school表中的地址栏位<br />
#表School的外键为SCHOOL_ADDRESS，它对应表Address的主键ADDRESS_ID<br />
（11）insert oneSchool———— sqlInsertRowString: <br />
update SCHOOL set SCHOOL_ADDRESS=? where SCHOOL_ID=? <br />
(仅仅update foreign-key的值。)<br />
（22）delete oneSchool———— sqlDeleteRowString: <br />
update SCHOOL set SCHOOL_ADDRESS=null where SCHOOL_ID=?<br />
（很奇怪，把foreign-key设置为null不知道有什么实际意义？）<br />
（33）delete 属于某一address的所有school ————sqlDeleteString：<br />
update SCHOOL set SCHOOL_ADDRESS=null where SCHOOL_ADDRESS=?<br />
（44）update ————sqlUpdateRowString：""， no need<br />
<br />
对many-to-many，对school set的改动，会改变关系表ADDRESS_SCHOOL中的数据:<br />
#&#8220;地区————学校&#8221;的关系为多对多的关系有点牵强，只是为了方便与上面的one-to-many作比较<br />
#假设有一个关系表ADDRESS_SCHOOL，有两个字段ADDRESS_ID, SCHOOL_ID，<br />
#这两个字段分别对应ADDRESS和SCHOOL两表的key<br />
（11）insert的SQL语句为： insert into ADDRESS_SCHOOL(ADDRESS_ID, SCHOOL_ID) <br />
values(?,?)<br />
（22）delete的SQL语句为： delete from ADDRESS_SCHOOL <br />
where ADDRESS_ID=? AND SCHOOL_ID=?<br />
（33）delete all的SQL语句为： delete from ADDRESS_SCHOOL<br />
where ADDRESS_ID=?<br />
（44）update的sql语句为 ————sqlUpdateRowString：<br />
update ADDRESS_SCHOOL set ADDRESS_ID=?<br />
where ADDRESS_ID=? AND SCHOOL_ID=?<br />
<br />
对set的操作(1),hibernate会执行(11)sqlInsertRowString<br />
对set的操作(2),hibernate会执行(22)sqlDeleteRowString<br />
对set的操作(3),hibernate会执行(33)sqlDeleteString<br />
对set的操作(4),老的schoolSet因为没有所属的address,所以被全部delete掉，即先执行(33)sqlDeleteString<br />
然后新增新的schoolSet,即再执行sqlInsertRowString<br />
对set的操作(5)，实际上就是将set从一个pojo转移到另一pojo：<br />
首先，执行sqlDeleteString，删除掉otherAddress所属的school<br />
然后，执行sqlDeleteString，删除掉address原先的school<br />
最后，执行sqlInsertRowString，将otherSchoolSet新增给address<br />
<br />
总结：（1）对one-to-many而言，改变set，会让hibernate执行一系列的update语句， 不会delete/insert数据<br />
（2）对many-to-many而言，改变set,只修改关系表的数据，不会影响many-to-many的另一方。<br />
（3）虽然one-to-many和many-to-many的数据库操作不一样，但目的都是一个：维护数据的一致性。执行的sql都<br />
只涉及到&#8220;桥字段&#8221;，不会考虑或改变其他的字段，所以对set的操作(6)是没有效果地。<br />
extend:对list,可能还会维护index字段。<br />
<br />
4.1.4 &#8220;inverse与cascade没有什么关系，互无牵扯。&#8221;<br />
commit后，这两个属性发挥作用的时机不同，hibernate会根据对pojo对象的改动，及cascade属性的设置，<br />
生成一系列的Action，比如UpdateAction,DeleteAction,InsertAction等，每个Action都有execute方法以执行对应的sql语句。<br />
待所有这些Action都生成好了后，hibernate再一起执行它们，在执行sql前，inverse属性起作用，<br />
当inverse=true时，不执行sql；当inverse=false时，执行sql。<br />
<br />
4.1.5 inverse的默认值为false，所以inverse属性默认会进行&#8220;关联更新&#8221;。<br />
<br />
4.1.6 建议：只对set + many-to-many设置inverse=false，其他的标记不考虑inverse属性。<br />
&nbsp; 糟糕的是，不设置inverse属性时，inverse默认为false。<br />
<br />
4.2. 级联（cascade）属性的作用： <br />
4.2.1 只有&#8220;关系标记&#8221;才有cascade属性：many-to-one，one-to-one ，any, <br />
set(map, bag, idbag, list, array) + one-to-many(many-to-many)<br />
<br />
4.2.2 级联指的是当主控方执行操作时，关联对象（被动方）是否同步执行同一操作。<br />
pojo和它的关系属性的关系就是&#8220;主控方 -- 被动方&#8221;的关系，如果关系属性是一个set，那么被动方就是set中的一个一个元素，。<br />
比如：学校（School）有三个属性：地区(Address),校长（TheMaster）和学生(Set， 元素为Student)<br />
执行session.delete(school)时，级联决定是否执行session.delete(Address),session.delete(theMaster)，<br />
是否对每个aStudent执行session.delete(aStudent)。<br />
<br />
extend:这点和inverse属性是有区别的。见4.3.<br />
<br />
4.2.3 一个操作因级联cascade可能触发多个关联操作。前一个操作叫&#8220;主控操作&#8221;，后一个操作叫&#8220;关联操作&#8221;。<br />
cascade属性的可选值：<br />
all : 所有情况下均进行关联操作。<br />
none：所有情况下均不进行关联操作。这是默认值。<br />
save-update:在执行save/update/saveOrUpdate时进行关联操作。<br />
delete：在执行delete时进行关联操作。 <br />
<br />
具体执行什么&#8220;关联操作&#8221;是根据&#8220;主控操作&#8221;来的：<br />
&#8220;主控操作&#8221; &nbsp; &nbsp; &nbsp; &#8220;关联操作&#8221;<br />
session.saveOrUpdate --&gt; session.saveOrUpdate (执行saveOrUpdate实际上会执行save或者update)<br />
session.save ----&gt; session.saveOrUpdate<br />
session.udpate --&gt; session.saveOrUpdate<br />
session.delete --&gt; session.delete<br />
<br />
4.2.4 主控操作和关联操作的先后顺序是&#8220;先保存one，再保存many；先删除many，再删除one；先update主控方，再update被动方&#8221;<br />
对于one-to-one，当其属性constrained="false"（默认值）时，它可看作one-to-many关系；<br />
&nbsp; 当其属性constrained="true"时，它可看作many-to-one关系；<br />
对many-to-many，它可看作one-to-many。<br />
<br />
比如：学校（School）有三个属性：地区(Address),校长（TheMaster，其constrained="false"）和学生(Set， 元素为Student) <br />
当执行session.save(school)时，<br />
实际的执行顺序为：session.save(Address);<br />
session.save(school);<br />
session.save(theMaster);<br />
for( 对每一个student ){<br />
session.save(aStudent);<br />
}<br />
<br />
当执行session.delete(school)时，<br />
实际的执行顺序为：session.delete(theMaster);<br />
for( 对每一个student ){<br />
session.delete(aStudent);<br />
}<br />
session.delete(school);<br />
session.delete(Address);<br />
<br />
当执行session.update(school)时，<br />
实际的执行顺序为：session.update(school);<br />
session.saveOrUpdate(Address);<br />
session.saveOrUpdate(theMaster);<br />
for( 对每一个student ){<br />
session.saveOrUpdate(aStudent);<br />
}<br />
注意：update操作因级联引发的关联操作为saveOrUpdate操作，而不是update操作。<br />
saveOrUpdate与update的区别是：前者根据操作对象是保存了还是没有保存，而决定执行update还是save<br />
<br />
extends: 实际中，删除学校不会删除地区，即地区的cascade一般设为false<br />
另外，many-to-many关系很少设置cascade=true，而是设置inverse=false。这个反映了cascade和inverse的区别。见4.3<br />
<br />
4.2.6 cascade的默认值为false，所以inverse属性默认会进行&#8220;关联更新&#8221;。<br />
<br />
4.2.7 总结：级联（cascade）就是操作一个对象时，对它的属性（其cascade=true）也进行这个操作。<br />
<br />
<br />
4.3 inverse和cascade的比较<br />
这两个属性本身互不影响，但起的作用有些类似，都能引发对关系表的更新。<br />
<br />
4.3.1 inverse只对set+one-to-many(或many-to-many)有效，对many-to-one, one-to-one无效。<br />
cascade对关系标记都有效。<br />
<br />
4.3.2 inverse对集合对象整体起作用，cascade对集合对象中的一个一个元素起作用，如果集合为空，那么cascade不会引发关联操作。<br />
比如将集合对象置为null， school.setStudentSet(null)<br />
inverse导致hibernate执行:udpate STUDENT set SCHOOL_ID=null where SCHOOL_ID=?<br />
cascade则不会执行对STUDENT表的关联更新， 因为集合中没有元素。<br />
<br />
再比新增一个school, session.save(school)<br />
inverse导致hibernate执行：<br />
for( 对(school的每一个student ){<br />
udpate STUDENT set SCHOOL_ID=? where STUDENT_ID=? //将学生的school_id改为新的school的id<br />
}<br />
cascade导致hibernate执行：<br />
for( 对school的每一个student ){<br />
session.save(aStudent); //对学生执行save操作<br />
}<br />
<br />
extends:如果改变集合中的部分元素（比如新增一个元素），<br />
inverse: hibernate先判断哪些元素改变了，对改变的元素执行相应的sql<br />
cascade: 它总是对集合中的每个元素执行关联操作。<br />
（在关联操作中，hibernate会判断操作的对象是否改变）<br />
<br />
4.3.2 两个起作用的时机不同：<br />
cascade：在对主控方操作时，级联发生。<br />
inverse: 在flush时（commit会自动执行flush)，对session中的所有set，hibernate判断每个set是否有变化，<br />
对有变化的set执行相应的sql，执行之前，会有个判断：if( inverse == true ) return;<br />
<br />
可以看出cascade在先，inverse在后。<br />
<br />
4.3.3 inverse 对set + one-to-many 和 set + many-to-many 起的作用不同。hibernate生成的sql不同。<br />
对one-to-many，hibernate对many方的数据库表执行update语句。<br />
对many-to-many, hibernate对关系表执行insert/update/delte语句，注意不是对many方的数据库表而是关系表。<br />
<br />
cascase 对set都是一致的，不管one-to-many还是many-to-many。都简单地把操作传递到set中的每个元素。所以它总是更新many<br />
方的数据库表。<br />
<br />
4.3.4 建议：只对set + many-to-many设置inverse=false，其他的标记不考虑inverse属性，都设为inverse=true。<br />
&nbsp; <br />
&nbsp; 对cascade，一般对many-to-one，many-to-many，constrained=true的one-to-one 不设置级联删除。</font>
<img src ="http://www.blogjava.net/lzn1446/aggbug/307122.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/lzn1446/" target="_blank">blue_leo</a> 2009-12-24 11:56 <a href="http://www.blogjava.net/lzn1446/articles/307122.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>