Hibernate抓取策略

官方文档相关部分:提升性能


抓取策略指多表关联查询的时候,Hibernate会发出多条sql进行查询,但如果设置了抓取策略,将多条SQL变成一条SQL执行,实际上就是使用join等关联查询。

 

如在一对多即示例Classes与Student的关联查询中:

代码:

Java代码   收藏代码
  1. public void testLoad(){  
  2.         Session session = null;  
  3.         try {  
  4.           
  5.             session = HibernateUtil.getSession();  
  6.             session.beginTransaction();  
  7.             //从classes得到student  
  8.             Classes cls = (Classes)session.load(Classes.class1);  
  9.             System.out.println(cls.getName());  
  10.             Set set = cls.getStudents();  
  11.             for (Iterator iterator = set.iterator(); iterator.hasNext();) {  
  12.                 Student object = (Student) iterator.next();  
  13.                 System.out.println(object.getName());  
  14.                   
  15.             }  
  16.               
  17.             HibernateUtil.commit(session);  
  18.         } catch (Exception e) {  
  19.             HibernateUtil.roolback(session);  
  20.         }finally{  
  21.             HibernateUtil.close(session);  
  22.         }  
  23.     }  

 

可以看到上面要打印出classes.name和classes.student.name那么默认情况下输出的SQL是:

Java代码   收藏代码
  1. Hibernate: select classes0_.id as id0_0_, classes0_.name as name0_0_ from t_classes classes0_ where classes0_.id=?  
  2. classes1  
  3. Hibernate: select students0_.class_id as class3_0_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.class_id as class3_1_0_ from t_student students0_ where students0_.class_id=?  
  4. stu4  
  5. stu2  
  6. stu1  
  7. stu0  
  8. stu3  

 

 

 

而我们可以使用抓取策略:

更改Classes.hbm.xml.在set中增加fetch属性

Java代码   收藏代码
  1. <hibernate-mapping package="com.lwf.hibernate.pojo">  
  2.     <class name="Classes" table="t_classes">  
  3.         <id name="id">  
  4.             <generator class="native"/>  
  5.         </id>  
  6.         <property name="name"/>  
  7.         <set name="students" fetch="join">  
  8.             <key column="class_id"/>  
  9.             <one-to-many class="Student"/>  
  10.         </set>  
  11.     </class>  
  12. </hibernate-mapping>  

 更改完后再测试上面的代码,只发出一条sql,结果为:

Java代码   收藏代码
  1. Hibernate: select classes0_.id as id0_1_, classes0_.name as name0_1_, students1_.class_id as class3_0_3_, students1_.id as id3_, students1_.id as id1_0_, students1_.name as name1_0_, students1_.class_id as class3_1_0_ from t_classes classes0_ left outer join t_student students1_ on classes0_.id=students1_.class_id where classes0_.id=?  
  2. classes1  
  3. stu2  
  4. stu4  
  5. stu1  
  6. stu3  
  7. stu0  

 

显然上面比较使用抓取策略后执行的SQL语句少了,性能也跟着提高了。。

上面我们是从Classes端得到Student所以在Classes.hbm.xml中的set里面加了fetch属性。

那么如果我们从Student端得到Classes要使用fetch怎么做呢?

测试方法:

Java代码   收藏代码
  1. public void testLoad1(){  
  2.         Session session = null;  
  3.         try {  
  4.           
  5.             session = HibernateUtil.getSession();  
  6.             session.beginTransaction();  
  7.               
  8.             Student s = (Student)session.load(Student.class1);  
  9.             System.out.println(s.getName());  
  10.             System.out.println(s.getClasses().getName());  
  11.               
  12.               
  13.             HibernateUtil.commit(session);  
  14.         } catch (Exception e) {  
  15.             HibernateUtil.roolback(session);  
  16.         }finally{  
  17.             HibernateUtil.close(session);  
  18.         }  
  19.     }  

 

默认情况下执行:发出两条SQL

Java代码   收藏代码
  1. Hibernate: select student0_.id as id1_0_, student0_.name as name1_0_, student0_.class_id as class3_1_0_ from t_student student0_ where student0_.id=?  
  2. stu0  
  3. Hibernate: select classes0_.id as id0_0_, classes0_.name as name0_0_ from t_classes classes0_ where classes0_.id=?  
  4. classes1  

 而要执行抓取策略,更改Student.hbm.xml的many-to-one

Java代码   收藏代码
  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping package="com.lwf.hibernate.pojo">  
  6.     <class name="Student" table="t_student">  
  7.     <!-- <cache usage="read-only"/> -->  
  8.         <id name="id">  
  9.             <generator class="native"/>  
  10.         </id>  
  11.         <property name="name"/>  
  12.         <many-to-one name="classes" column="class_id" fetch="join"></many-to-one>  
  13.     </class>  
  14. </hibernate-mapping>  

 

上面我们增加了fetch="join"属性

结果:

Java代码   收藏代码
  1. Hibernate: select student0_.id as id1_1_, student0_.name as name1_1_, student0_.class_id as class3_1_1_, classes1_.id as id0_0_, classes1_.name as name0_0_ from t_student student0_ left outer join t_classes classes1_ on student0_.class_id=classes1_.id where student0_.id=?  
  2. stu0  
  3. classes1  

 

现在只执行一条SQL了。。。

 

需要提示的是其实默认情况下fetch="select"


在Classes与Student一对多映射中,我们将Set里面的fetch属性设置为subselect来实现子查询。

如下示例

首先看一下set中fetch="select"即默认情况下:

生成数据类:

Java代码   收藏代码
  1. package com.bjsxt.hibernate;  
  2.   
  3. import org.hibernate.Session;  
  4.   
  5. public class InitData {  
  6.   
  7.     public static void main(String[] args) {  
  8.         Session session = HibernateUtils.getSession();  
  9.         try {  
  10.             session.beginTransaction();  
  11.             for(int i=0; i<10; i++){  
  12.                 Classes classes = new Classes();  
  13.                 classes.setName("班级"+i);  
  14.                 session.save(classes);  
  15.                 for(int j=0; j<10; j++){  
  16.                     Student student = new Student();  
  17.                     student.setName("班级"+i+"的学生"+j);  
  18.                     //在内存中建立由student指向classes的引用  
  19.                     student.setClasses(classes);  
  20.                     session.save(student);  
  21.                 }  
  22.             }  
  23.             session.getTransaction().commit();  
  24.         } catch (Exception e) {  
  25.             e.printStackTrace();  
  26.             session.getTransaction().rollback();  
  27.         } finally{  
  28.             HibernateUtils.closeSession(session);  
  29.         }  
  30.     }  
  31.   
  32. }  

 

测试类:

Java代码   收藏代码
  1. package com.bjsxt.hibernate;  
  2.   
  3. import java.io.Serializable;  
  4. import java.util.Iterator;  
  5. import java.util.List;  
  6. import java.util.Set;  
  7.   
  8. import org.hibernate.Session;  
  9.   
  10. import junit.framework.TestCase;  
  11.   
  12. public class FetchTest extends TestCase {  
  13.   
  14.     public void testFetch1() {  
  15.         Session session = null;  
  16.         try {  
  17.             session = HibernateUtils.getSession();  
  18.             Classes classes = (Classes)session.load(Classes.class1);  
  19.             System.out.println("班级:" + classes.getName());  
  20.             Set students = classes.getStudents();  
  21.             for (Iterator iter = students.iterator(); iter.hasNext();) {  
  22.                 Student student = (Student)iter.next();  
  23.                 System.out.println(student.getName());  
  24.             }  
  25.         }catch(Exception e) {  
  26.             e.printStackTrace();  
  27.         }finally {  
  28.             HibernateUtils.closeSession(session);  
  29.         }  
  30.     }  
  31.       
  32.     public void testFetch2() {  
  33.         Session session = null;  
  34.         try {  
  35.             session = HibernateUtils.getSession();  
  36.             List Classes = session.createQuery("select c from Classes c where c.id in(1, 2, 3)").list();  
  37.             for (Iterator iter = Classes.iterator(); iter.hasNext();) {  
  38.                 Classes cls = (Classes)iter.next();  
  39.                 System.out.println("班级:" + cls.getName());  
  40.                 for (Iterator iter1 = cls.getStudents().iterator(); iter1.hasNext();) {  
  41.                     Student student = (Student)iter1.next();  
  42.                     System.out.println(student.getName());  
  43.                 }  
  44.             }  
  45.         }catch(Exception e) {  
  46.             e.printStackTrace();  
  47.         }finally {  
  48.             HibernateUtils.closeSession(session);  
  49.         }  
  50.     }  
  51.       
  52. }  

 

分别列出方法一与方法二的测试结果:

Java代码   收藏代码
  1. Hibernate: select classes0_.id as id0_0_, classes0_.name as name0_0_ from t_classes classes0_ where classes0_.id=?  
  2. 班级:班级0  
  3. Hibernate: select students0_.classid as classid0_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.classid as classid1_0_ from t_student students0_ where students0_.classid=?  
  4. 班级0的学生8  
  5. 班级0的学生1  
  6. 班级0的学生7  
  7. 班级0的学生5  
  8. 班级0的学生3  
  9. 班级0的学生4  
  10. 班级0的学生0  
  11. 班级0的学生6  
  12. 班级0的学生9  
  13. 班级0的学生2  

 

Java代码   收藏代码
  1. Hibernate: select classes0_.id as id0_, classes0_.name as name0_ from t_classes classes0_ where classes0_.id in (1 , 2 , 3)  
  2. 班级:班级0  
  3. Hibernate: select students0_.classid as classid0_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.classid as classid1_0_ from t_student students0_ where students0_.classid=?  
  4. 班级0的学生7  
  5. 班级0的学生2  
  6. 班级0的学生3  
  7. 班级0的学生1  
  8. 班级0的学生0  
  9. 班级0的学生9  
  10. 班级0的学生4  
  11. 班级0的学生8  
  12. 班级0的学生6  
  13. 班级0的学生5  
  14. 班级:班级1  
  15. Hibernate: select students0_.classid as classid0_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.classid as classid1_0_ from t_student students0_ where students0_.classid=?  
  16. 班级1的学生9  
  17. 班级1的学生0  
  18. 班级1的学生6  
  19. 班级1的学生8  
  20. 班级1的学生7  
  21. 班级1的学生2  
  22. 班级1的学生5  
  23. 班级1的学生3  
  24. 班级1的学生1  
  25. 班级1的学生4  
  26. 班级:班级2  
  27. Hibernate: select students0_.classid as classid0_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.classid as classid1_0_ from t_student students0_ where students0_.classid=?  
  28. 班级2的学生6  
  29. 班级2的学生9  
  30. 班级2的学生3  
  31. 班级2的学生1  
  32. 班级2的学生2  
  33. 班级2的学生7  
  34. 班级2的学生8  
  35. 班级2的学生4  
  36. 班级2的学生0  
  37. 班级2的学生5  

 

下面更改fetch="subselect"

Java代码   收藏代码
  1. <?xml version="1.0"?>  
  2. <!DOCTYPE hibernate-mapping PUBLIC   
  3.     "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
  4.     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
  5. <hibernate-mapping>  
  6.     <class name="com.bjsxt.hibernate.Classes" table="t_classes">  
  7.         <id name="id">  
  8.             <generator class="native"/>  
  9.         </id>  
  10.         <property name="name"/>  
  11.         <!--   
  12.             <set name="students" cascade="all" order-by="id">  
  13.          -->  
  14.          <set name="students" inverse="true" fetch="subselect">  
  15.             <key column="classid"/>  
  16.             <one-to-many class="com.bjsxt.hibernate.Student"/>  
  17.         </set>  
  18.     </class>  
  19. </hibernate-mapping>  

 

同样,将两个方法的测试结果列出如下:

Java代码   收藏代码
  1. Hibernate: select classes0_.id as id0_0_, classes0_.name as name0_0_ from t_classes classes0_ where classes0_.id=?  
  2. 班级:班级0  
  3. Hibernate: select students0_.classid as classid0_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.classid as classid1_0_ from t_student students0_ where students0_.classid=?  
  4. 班级0的学生3  
  5. 班级0的学生1  
  6. 班级0的学生9  
  7. 班级0的学生7  
  8. 班级0的学生5  
  9. 班级0的学生0  
  10. 班级0的学生6  
  11. 班级0的学生2  
  12. 班级0的学生8  
  13. 班级0的学生4  

 

Java代码   收藏代码
  1. Hibernate: select classes0_.id as id0_, classes0_.name as name0_ from t_classes classes0_ where classes0_.id in (1 , 2 , 3)  
  2. 班级:班级0  
  3. Hibernate: select students0_.classid as classid0_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.classid as classid1_0_ from t_student students0_ where students0_.classid in (select classes0_.id from t_classes classes0_ where classes0_.id in (1 , 2 , 3))  
  4. 班级0的学生5  
  5. 班级0的学生1  
  6. 班级0的学生0  
  7. 班级0的学生8  
  8. 班级0的学生7  
  9. 班级0的学生2  
  10. 班级0的学生9  
  11. 班级0的学生6  
  12. 班级0的学生4  
  13. 班级0的学生3  
  14. 班级:班级1  
  15. 班级1的学生5  
  16. 班级1的学生1  
  17. 班级1的学生0  
  18. 班级1的学生7  
  19. 班级1的学生4  
  20. 班级1的学生9  
  21. 班级1的学生8  
  22. 班级1的学生3  
  23. 班级1的学生6  
  24. 班级1的学生2  
  25. 班级:班级2  
  26. 班级2的学生0  
  27. 班级2的学生5  
  28. 班级2的学生1  
  29. 班级2的学生8  
  30. 班级2的学生6  
  31. 班级2的学生9  
  32. 班级2的学生4  
  33. 班级2的学生7  
  34. 班级2的学生3  
  35. 班级2的学生2  

 

比较两次测试的结果我们发现,方法二的输出结果不同,当fetch="subselect"的时候,方法二进行了子查询

如:

Java代码   收藏代码
  1. Hibernate: select students0_.classid as classid0_1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.classid as classid1_0_ from t_student students0_ where students0_.classid in (select classes0_.id from t_classes classes0_ where classes0_.id in (1 , 2 , 3))  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值