Hibernate 检索策略之检索策略属性 Lazy,策略属性 batch-size,检索策略属性Fetch详解        ,

第一节:检索策略属性 Lazy

举例说明:

采用Class和Student—  1 对 多的关系;

Student.java:

package com.cy.model;

public class Student {
    private int id;
    private String name;
    private Class c;
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Class getC() {
        return c;
    }
    public void setC(Class c) {
        this.c = c;
    }
    
    
}

Class.java:

package com.cy.model;

import java.util.HashSet;
import java.util.Set;

public class Class {
    private int id;
    private String name;
    private Set<Student> students = new HashSet<Student>();
    
    
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Set<Student> getStudents() {
        return students;
    }
    public void setStudents(Set<Student> students) {
        this.students = students;
    }
    
    
}

Student.hbm.xml:

扫描二维码关注公众号,回复: 5810152 查看本文章
<hibernate-mapping package="com.cy.model">

    <class name="Student" table="t_student">
        <id name="id" column="stuId">
            <generator class="native"></generator>
        </id>
        <property name="name" column="stuName"></property>
        
        <many-to-one name="c" column="classId" class="com.cy.model.Class" cascade="save-update" lazy="proxy"></many-to-one>
        
    </class>

</hibernate-mapping>

Class.hbm.xml:

<hibernate-mapping package="com.cy.model">

    <class name="Class" table="t_class">
        <id name="id" column="classId">
            <generator class="native"></generator>
        </id>
        <property name="name" column="className"></property>
        
        <set name="students" cascade="save-update" inverse="true" lazy="false" batch-size="3" fetch="join">
            <key column="classId"></key>
            <one-to-many class="com.cy.model.Student" />
        </set>
    </class>

</hibernate-mapping>

第一节:检索策略属性 Lazy

Lazy:true (默认) 延迟检索 ;set 端 一对多
Lazy:false 立即检索;set 端 一对多
Lazy:extra 增强延迟检索; set 端 一对多
Lazy:proxy(默认) 延迟检索;many-to-one 多对一
Lazy:no-proxy 无代理延迟检索;many-to-one 多对一 (需要编译时字节码增强)

    @Test
    public void testLazy1(){
        //因为在class.hbm中set端,一对多,配置的是lazy=true,加载class的时候,默认是不加载学生的。
        Class c = (Class) session.get(Class.class, 1);    
        
     
        Set<Student> students = c.getStudents();//查询student数据,才开始加载
        
        System.out.println(students.size());
        
      Iterator it = students.iterator();
        
    }

lazy:false: 查询class,如果肯定会用到student信息的话,可以立即检索;

lazy:extra:也是延迟的,但是增强的;

举例:配置lazy为true的话,想知道查询出来学生数量的话:

Class c = (Class) session.get(Class.class, 1);

Set<Student> students = c.getStudents();

System.out.println(students.size());

发出的sql为查询所有学生,然后知道3条记录;

但是其实只需要select count(*) from student就行了,这就是sql优化。配置lazy=extra就能实现;

但是实际开发中因为很少只查询size的情况,所以不常用

lazy:proxy:

取Student信息的时候,里面的班级Class是代理类,是不包含数据的;但是用到Class里面内容的时候,就通过代理类去数据库查询内容了。

    @Test
    public void testLazy2(){
        //many to one端,默认lazy - proxy。取出的student中的Class是一个代理类。没有实际数据
        Student student = (Student) session.get(Student.class, 1);
        
        //等到用到class的名字的时候,代理类才去发出sql查询数据。
        student.getC().getName();
    }

lazy:no-proxy:

没有代理类,取student的时候,里面的class是个null值,等到用class内容再去查。

第二节:策略属性 batch-size                                         

1,批量延迟检索;

对应的class.hbm配置:lazy="true" batch-size="3"

复制代码

/**
     * 批量延迟检索,lazy=true
     */
    @Test
    public void testBatch1(){
        List<Class> classList = session.createQuery("from Class").list();
        Iterator<Class> it = classList.iterator();
        Class c1 = it.next();
        Class c2 = it.next();
        Class c3 = it.next();
        c1.getStudents().iterator();
        c2.getStudents().iterator();
        c3.getStudents().iterator();
        
        //先取出所有class,因为set students端配置了lazy=false
        //等到c1、c2、c3用到student的时候,才去查找。每个发出一条sql语句。
        //假如classList很多很多的话,遍历每个class,然后取每个class下面的students,每个都发出一条sql,这样效率就很低了。
        //所以,引入了batch-size,批量检索。batch-size的值为批量的值
        
        //在class.hbm.  set studens端,配置batch-size=3,发出的sql就是这样了:
        /**
         * SELECT 
                t_student.classId , 
                t_student.stuId , 
                t_student.stuName
            FROM t_student
            WHERE t_student.classId IN (1, 2, 3)
         */
    }

而未设置批量检索batch-size,发出的sql是下面这样,一条一条的查:

设置了批量检索,batch-size=3后,查询student信息时,一次查3条;

2,批量立即检索;

@Test
    public void testBatch2(){
        List<Class> classList = session.createQuery("from Class").list();
        //这里class.hbm.xml set students中配置lazy=false,batch-size=3,就是批量立即检索了.
        //发出的批量sql和上面一样。
    
    }

第三节:检索策略属性Fetch   

1,Fetch:select(默认) 查询方式;
2,Fetch:subselect 子查询方式;
3,Fetch:join 迫切左外连接查询方式;

                                   

Fetch这里也是在class端配置的;

fetch:subselect,在数据量很大的时候,使用子查询,可以使性能得到优化点。

复制代码

@Test
    public void testFetch1(){
        List<Class> classList = session.createQuery("from Class").list();
        Iterator<Class> it = classList.iterator();
        Class c1 = it.next();
        Class c2 = it.next();
        Class c3 = it.next();
        c1.getStudents().iterator();
        c2.getStudents().iterator();
        c3.getStudents().iterator();
        /**
         * class.hbm set students 配置fetch="select",是默认的,发出的sql:
         * SELECT 
                t_student.classId , 
                t_student.stuId , 
                t_student.stuName
            FROM t_student
            WHERE t_student.classId IN (1, 2, 3)
            
            
            现在改为fetch=subselect:sql变成了:
            SELECT 
                t_student.classId , 
                t_student.stuId , 
                t_student.stuName
            FROM t_student
            WHERE t_student.classId IN
            (SELECT classId FROM t_class )
         * 
         */
    }

fetch:join:

@Test
    public void testFetch2(){
        Class c = (Class) session.get(Class.class, 1);
        /**
         * 这里class.hbm配置:<set name="students" lazy="false" fetch="join">
         * 查询班级的时候,把属于这个班级的学生也一起查出来,这里fetch=join,sql中left outer join:
         * 发出的sql:
         * SELECT
                t_class.classId,
                t_class.className,
                t_student.stuId,
                t_student.stuName,
                t_student.classId
            FROM t_class
            LEFT OUTER JOIN t_student ON t_class.classId = t_student.classId
            WHERE t_class.classId = 1
            
         * 可以看到只发出一条sql语句了,t_class表和t_student表关联,将class信息和student信息一起取了出来;
         * 
         * 而如果fetch为select,是先取班级信息;再取student信息
         */
    }

猜你喜欢

转载自blog.csdn.net/qq_40135955/article/details/89046678