抓取策略

来源:互联网 发布:python调用qq发送消息 编辑:程序博客网 时间:2024/06/04 23:35

首先要搞清楚:

抓取就是查询嘛,查询关联对象.可以决定如何抓取关联对象.fetch=slect的意思是另外发送一条语句加载其关联对象及集合.

主要有单端代理即many-to-one这种类型的,集合代理,批量抓取

单端代理的批量抓取:fetch有三,一种是不填,一种是填select,还有一种是填join

1.保持默认,同fetch="select",如:
<many-to-one name="classes" column="classesid" fetch="select"/>,fetch="select",另外发送一条select语句加载当前对象的关联对象或集合

fetch为select或join不影响hql,它影响的是load,get方法,此时lazy是不会失效的

      //会发送sql语句的

      Student student = (Student)session.load(Student.class, 1);
System.out.println("student.name=" + student.getName());
//会发送sql语句的
Classes classes = student.getClasses();
System.out.println("classes.name=" + classes.getName());

2.设置fetch="join"如:<many-to-one name="classes" column="classesid" fetch="join"/>,fetch="join",hibernate会通过一个select语句连接(内联/外联)抓取其关联对象或集合

fetch="join",那么lazy失效
fetch="join",只影响get和load,对hql没有影响

      Student student = (Student)session.load(Student.class, 1);

//发送一条sql语句:select student0_.id as id1_1_, student0_.name as name1_1_, student0_.classesid as classesid1_1_, classes1_.id as id0_0_, classes1_.name as //name0_0_ from t_student student0_ inner join t_classes classes1_ on student0_.classesid=classes1_.id where student0_.id=?
System.out.println("student.name=" + student.getName());

Classes classes = student.getClasses();

                        //这里不会发Sql语句了
System.out.println("classes.name=" + classes.getName());

采用hql:

      //会发送一条语句

      Student student = (Student)session.createQuery("select s from Student s join s.classes where  s.id=1").list().get(0);
System.out.println("student.name=" + student.getName());

Classes classes = student.getClasses();

                         //会发送一条语句
System.out.println("classes.name=" + classes.getName());

如果用以下的hql语句则不会发送两条语句:这叫预加载,注意预加载的时候fetch不能fetch他的集合的,这样会出错的,而要反过来.

Student student = (Student)session.createQuery("select s from Student s join fetch s.classes where  s.id=1").list().get(0);


集合代理的批量抓取:fetch的取值有四,一种是默认的不填写,一种是fetch=select,一种是fetch=join,还有一种是fetch=

1.保持默认,同fetch="select",如:
<set name="students" order-by="id" inverse="true" cascade="all" fetch="select">
fetch="select",另外发送一条select语句加载当前对象的关联对象或集合,如下会发送两条sql语句

      Classes classes = (Classes)session.load(Classes.class, 1);
System.out.println(classes.getName());

for (Iterator iter=classes.getStudents().iterator(); iter.hasNext();) {
Student student = (Student)iter.next();
System.out.println(student.getName());
}

2.设置fetch="join",如:<set name="students" order-by="id" inverse="true" cascade="all" fetch="join">
fetch="join",hibernate会通过一个select语句连接(内联/外联)抓取其关联对象或集合
fetch="join",那么lazy失效
fetch="join",只影响get和load,对hql没有影响

3.设置fetch="subselect",如:
<set name="students" order-by="id" inverse="true" cascade="all" fetch="subselect">
fetch="subselect",另外发送一条select语句抓取在前面查询到的所有实体的关联集合
fetch="subselect",会影响hql查询,会发送一条子查询语句.

      Classes classes = (Classes)session.load(Classes.class, 1);

      //发送一条查询实体的sql语句
System.out.println(classes.getName());
                       //发送一条查询前面查询到的classes实体所关联的集合
for (Iterator iter=classes.getStudents().iterator(); iter.hasNext();) {
Student student = (Student)iter.next();
System.out.println(student.getName());
}

以下用hql语句:

                       List classesList = session.createQuery("select c from Classes c where c.id in(1, 2, 3)").list();
for (Iterator iter1=classesList.iterator(); iter1.hasNext();) {
Classes classes = (Classes)iter1.next();
System.out.println(classes.getName());

    //这里会发出一条子查询的语句

//select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.classesid as //classesid1_0_ from t_student students0_ where students0_.classesid in (select classes0_.id from t_classes classes0_ where classes0_.id in (1 , 2 , 3)) //order by students0_.id

for (Iterator iter=classes.getStudents().iterator(); iter.hasNext();) {
Student student = (Student)iter.next();
System.out.println(student.getName());
}
}    

batch-size的用法,即是批量抓取

1.batch-size在<class>的应用

batch-size属性,可以批量加载实体类,参见Classes.hbm.xml,<class name="com.bjpowernode.hibernate.Classes" table="t_classes" batch-size="10">,加载班级的时候成10个一批进行加载.测试如下:

先不设置batch-size="10"

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 student = (Student)iter.next();
System.out.println(student.getName());
System.out.println(student.getClasses().getName());
}

那么这样会发生N+1的问题,

查询10个学生显示到列表中:
  * 首先会发出查询学生的sql语句
  * 然后会发出根据班级id查询班级的sql语句
  这样就会导致N+1问题,也就是发出了N+1条语句,会严重影响性能

解决方法其实有二种:一种是采用使用fetch预抓取Classes,如下:

List students = session.createQuery("select s from Student s join fetch s.classes  where s.id in(:ids)")
.setParameterList("ids", new Object[]{1, 11, 21, 31, 41, 51, 61, 71, 81, 91})
.list();

一种是采用批量抓取策略:<class name="com.bjpowernode.hibernate.Classes" table="t_classes" batch-size="10">

2.batch-size在集合上的应用

batch-size属性,可以批量加载实体类,<set name="students" order-by="id" inverse="true" cascade="all" batch-size="3">

List classesList = session.createQuery("select c from Classes c").list();

for (Iterator iter1=classesList.iterator(); iter1.hasNext();) {
Classes classes = (Classes)iter1.next();
System.out.println(classes.getName());
for (Iterator iter=classes.getStudents().iterator(); iter.hasNext();) {
Student student = (Student)iter.next();
System.out.println(student.getName());
}

}

生成的语句是这样的:

select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.classesid as classesid1_0_ from t_student students0_ where students0_.classesid in (?, ?, ?) order by students0_.id

如果不设置batch-size="3",那么会发出10条语句的,生成的语句如下:

select students0_.classesid as classesid1_, students0_.id as id1_, students0_.id as id1_0_, students0_.name as name1_0_, students0_.classesid as classesid1_0_ from t_student students0_ where students0_.classesid=? order by students0_.id

原创粉丝点击