hibernate抓取策略(fetch)

抓取策略(fetching strategy) 是指:當應用程序需要在(Hibernate實體對象圖的)關聯關
系間進行導航的時候, Hibernate如何獲取關聯對象的策略。抓取策略可以在O/R映射的元數據中聲明,
也可以在特定的HQL 或條件查詢(Criteria Query)中重載聲明。隻影響get load 方法,對hql是不影響的,除了有一個之外。 
例如,經典的班級對學生是一對多關聯,我配置的時候採取的是一對多雙向關聯。主要是它的關聯對象的加載。
(1):單端代理的批量抓取
如果沒有配置抓取策略,默認的fetch="select",即:另外發送一條 SELECT 語句抓取當前對象的關聯實體或集合
Student stu = (Student) session.load(Student.class, 1);
  System.out.println(stu.getName());
  System.out.println(stu.getClasses().getName());

看執行後發的SQL語句:
Hibernate: select student0_.id as id0_0_, student0_.name as name0_0_, student0_.classesid as classesid0_0_ from t_student student0_ where student0_.id=?
班級0學生0
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=?
班級0
從發的SQL語句可以看出,第一條語句是通過students表來查詢的,
當我們想去加載它的關聯對象classes時,發出第二條語句,是從classes表裏查尋得

如果我設置抓取策略爲join,即:<many-to-one name="classes" column="classesid" fetch="join"></many-to-one>
執行之後,你會發現發出的SQL語句:
Hibernate: select student0_.id as id0_1_, student0_.name as name0_1_, student0_.classesid as classesid0_1_, classes1_.id as id1_0_, classes1_.name as name1_0_ from t_student student0_ left outer join t_classes classes1_ on student0_.classesid=classes1_.id where student0_.id=?
班級0學生0
班級0
fetch="join"的意思是 :Hibernate通過 在SELECT語句使用OUTER JOIN(外連接)來 獲得對象的關聯實例或者關聯集合
你看我們上面發出的SQL語句,就是個左外連接查詢,把學生對應得班級也加載了,所以,它的lazy就失效了。
(2)集合上的抓取策略:(有三種策略,select,join,subselect)
Classes classes = (Classes) session.load(Classes.class, 1);
  System.out.println(classes.getName());
  for(Iterator iter = classes.getStudents().iterator();iter.hasNext();){
   Student stu = (Student) iter.next();
   System.out.println(stu.getName());
  }
如果沒有配置抓取策略,默認的fetch="select",
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=?
班級0
Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id0_0_, students0_.name as name0_0_, students0_.classesid as classesid0_0_ from t_student students0_ where students0_.classesid=?
班級0學生5
班級0學生1
默認發出兩條select語句。
當設置抓取策略fetch="join":<set name="students" inverse="true" fetch="join">
Hibernate: select classes0_.id as id1_1_, classes0_.name as name1_1_, students1_.classesid as classesid3_, students1_.id as id3_, students1_.id as id0_0_, students1_.name as name0_0_, students1_.classesid as classesid0_0_ from t_classes classes0_ left outer join t_student students1_ on classes0_.id=students1_.classesid where classes0_.id=?
班級0
班級0學生7
班級0學生3
會發現只發出一條外連接語句,加載它的關聯實體,此時,lazy也失效了。
如果設置抓取策略爲:<set name="students" inverse="true" fetch="subselect">
另外發送一條SELECT 語句抓取在前面查詢到(或者抓取到)的所有實體對象的關聯集合。(注意,它是從前面查詢到的)
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=?
班級0
Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id0_0_, students0_.name as name0_0_, students0_.classesid as classesid0_0_ from t_student students0_ where students0_.classesid=?
班級0學生5
班級0學生1
仔細看它發出的SQL語句:跟我們默認的select策略一模一樣,但是,它會影響我們的HQL查詢,如:
List classesList = session.createQuery("select c from Classes c where c.id in(1, 2, 3)").list();
  for (Iterator iter=classesList.iterator(); iter.hasNext();) {
   Classes classes = (Classes)iter.next();
   System.out.println("classes.name=" + classes.getName());
   for (Iterator iter1=classes.getStudents().iterator(); iter1.hasNext();) {
    Student student = (Student)iter1.next();
    System.out.println("student.name=" + student.getName());
   }
  }
看它發的SQL語句,另外分別發了三條select語句,
Hibernate: select classes0_.id as id1_, classes0_.name as name1_ from t_classes classes0_ where classes0_.id in (1 , 2 , 3)
classes.name=班級0
Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id0_0_, students0_.name as name0_0_, students0_.classesid as classesid0_0_ from t_student students0_ where students0_.classesid=?
student.name=班級0學生6
student.name=班級0學生0

classes.name=班級1
Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id0_0_, students0_.name as name0_0_, students0_.classesid as classesid0_0_ from t_student students0_ where students0_.classesid=?
student.name=班級1學生5
student.name=班級1學生9
st
classes.name=班級2
Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id0_0_, students0_.name as name0_0_, students0_.classesid as classesid0_0_ from t_student students0_ where students0_.classesid=?
student.name=班級2學生0
student.name=班級2學生7
如果設置<set name="students" inverse="true" fetch="subselect">
Hibernate: select classes0_.id as id1_, classes0_.name as name1_ from t_classes classes0_ where classes0_.id in (1 , 2 , 3)
classes.name=班級0
Hibernate: select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id0_0_, students0_.name as name0_0_, students0_.classesid as classesid0_0_ from t_student students0_ where students0_.classesid in (select classes0_.id from t_classes classes0_ where classes0_.id in (1 , 2 , 3))
student.name=班級0學生4
student.name=班級0學生3
另外只需發一條SQL語句,仔細看看他的SQL語句,從from之後看:用了一個子查詢,from t_student students0_ where students0_.classesid in (select classes0_.id from t_classes classes0_ where classes0_.id in (1 , 2 , 3))。

下面講解下批量抓取策略:
List students = session.createQuery("select s from Student s where s.id in(:ids)")
       .setParameterList("ids", new Object[]{1,11,21,31,41,51,61,71,81,91})
       .list();
  for (Iterator iter=students.iterator(); iter.hasNext();) {
   Student stu =(Student)iter.next();
   System.out.println("classes.name=" + stu.getName());
   System.out.println("student.name=" + stu.getClasses().getName());
   
  }
我發出的SQL語句有10條
Hibernate: select student0_.id as id0_, student0_.name as name0_, student0_.classesid as classesid0_ from t_student student0_ where student0_.id in (? , ? , ? , ? , ? , ? , ? , ? , ? , ?)
classes.name=班級0學生0
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=?
student.name=班級0
classes.name=班級1學生0
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=?
student.name=班級1
classes.name=班級2學生0
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=?
student.name=班級2
classes.name=班級3學生0
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=?
student.name=班級3
classes.name=班級4學生0
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=?
student.name=班級4
classes.name=班級5學生0
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=?
student.name=班級5
classes.name=班級6學生0
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=?
student.name=班級6
classes.name=班級7學生0
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=?
student.name=班級7
classes.name=班級8學生0
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=?
student.name=班級8
classes.name=班級9學生0
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id=?
student.name=班級9
如果我在班級那裏設置一下:<class name="Classes" table="t_classes" batch-size="5">
結果,看看效果就知道了,它會5條一次抓取,而不會一次一條的從數據庫裏取。
Hibernate: select student0_.id as id0_, student0_.name as name0_, student0_.classesid as classesid0_ from t_student student0_ where student0_.id in (? , ? , ? , ? , ? , ? , ? , ? , ? , ?)
classes.name=班級0學生0
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id in (?, ?, ?, ?, ?)
student.name=班級0
classes.name=班級1學生0
student.name=班級1
classes.name=班級2學生0
student.name=班級2
classes.name=班級3學生0
student.name=班級3
classes.name=班級4學生0
student.name=班級4
classes.name=班級5學生0
Hibernate: select classes0_.id as id1_0_, classes0_.name as name1_0_ from t_classes classes0_ where classes0_.id in (?, ?, ?, ?, ?)
student.name=班級5
classes.name=班級6學生0
student.name=班級6
classes.name=班級7學生0
student.name=班級7
classes.name=班級8學生0
student.name=班級8
classes.name=班級9學生0
student.name=班級9

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章