1. 程式人生 > >Hibernate學習9—檢索策略

Hibernate學習9—檢索策略

sna outer view logs pla 成了 rom app -s

本章,采用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; } }
View Code

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; } }
View Code

Student.hbm.xml:

技術分享
<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>
View Code

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>
View Code

第一節:檢索策略屬性Lazy                                                  

技術分享

Lazy:true:默認延遲檢索:用到才加載

技術分享
    @Test
    public void testLazy1(){
        //因為在class.hbm中set端,一對多,配置的是lazy=true,加載class的時候,默認是不加載學生的。
        Class c = (Class) session.get(Class.class, 1);    
        
        //等到什麽時候會查詢學生數據?——等到他用的時候
        //等到用到的時候才去檢索,這就是延遲檢索
        Set<Student> students = c.getStudents();
        
        System.out.println(students.size());
        
//        Iterator it = students.iterator();
        
    }
View Code lazy:false: 查詢class,如果肯定會用到student信息的話,可以立即檢索;設置lazy false也行的 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();
    }
View Code 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)
         */
    }
View Code

而未設置批量檢索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和上面一樣。
    
    }
View Code

第三節:檢索策略屬性Fetch                                      

技術分享

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 )
         * 
         */
    }
View Code

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信息
         */
    }
View Code

Hibernate學習9—檢索策略