hibernate抓取策略(fetch)

来源:互联网 发布:64码高清网络电视apk 编辑:程序博客网 时间:2024/05/17 09:06

抓取策略(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

0 0
原创粉丝点击