SSH笔记-检索策略(lazy、fetch、batch-size)

1、分为两部分:
①类级别检索策略,大概了解检索策略(代码所在包com.demo.sshtest)
②检索策略的lazy、fetch、batch-size属性使用(代码所在包com.demo.sshtest2)

2、检索策略:
①立即检索,立即加载检索方法指定的对象
②延迟检索,延迟加载检索方法指定的对象,在使用具体属性值时,才进行加载(这个时候会执行查询语句)

3、检索策略使用场景:
①如果加载对象是为了访问他的属性,则使用立即加载
②如果加载对象目的是为了获得他的应用,则可以使用延迟加载

4、检索策略属性:
①lazy: 主要决定 orders 集合被初始化的时机. 即到底是在加载 Customer 对象时就被初始化, 还是在程序访问 orders 集合时被初始化
②fetch: 取值为 “select” 或 “subselect” 时, 决定初始化 orders 的查询语句的形式; 若取值为”join”, 则决定 orders 集合被初始化的时机,若把 fetch 设置为 “join”, lazy 属性将被忽略
③batch-size:批量检索能减少 SELECT 语句的数目, 提高延迟检索或立即检索的运行性能

5、一对多和多对多的检索策略,lazy和fetch取值对应策略
①lazy=true ——– fatch=默认 ——– 采用延迟检索
②lazy=false ——– fatch=默认 ——– 采用立即检索
③lazy=extra ——– fatch=默认 ——– 采用加强延迟检索(延迟对象集合初始化时机)
④lazy=true/false/extra ——– fatch=默认 ——– 根据lazy决定执行检索策略
⑤lazy=true/false/extra ——– fatch=subselect ——– 根据lazy决定执行检索策略
⑥lazy=默认 ——– fatch=join ——– 采用迫切左外连接策略

6、多对一和一对一的检索策略,lazy和fetch取值对应策略
①lazy=proxy ——– fetch=默认 ——– 采用延迟检索
②lazy=non-proxy ——– fetch=默认 ——– 采用无代理延迟检索(需要增强持久化类的字节码才能实现)
③lazy=false ——– fetch=默认 ——– 采用立即检索
④lazy=默认 ——– fetch=join ——– 采用迫切左外连接策略(比立即检索用更少select语句)


7、类级别检索策略
(1)Customer.java “一”端(因为关系配置有用set)

package com.demo.sshtest;

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

public class Customer {

    public Integer Id;
    public String cName;

    public Set<Merchant>merchant = new HashSet<>();

    public Integer getId() {
        return Id;
    }
    public void setId(Integer id) {
        Id = id;
    }
    public String getcName() {
        return cName;
    }
    public void setcName(String cName) {
        this.cName = cName;
    }
    public Set<Merchant> getMerchant() {
        return merchant;
    }
    public void setMerchant(Set<Merchant> merchant) {
        this.merchant = merchant;
    }

}

(2)Merchant.java “多”端

package com.demo.sshtest;

public class Merchant {

    public Integer merId;
    public String merName;
    public Integer getMerId() {
        return merId;
    }
    public void setMerId(Integer merId) {
        this.merId = merId;
    }
    public String getMerName() {
        return merName;
    }
    public void setMerName(String merName) {
        this.merName = merName;
    }

}

(3)Customer.hbm.xml 多端映射关系配置文件

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-4-12 22:01:32 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="com.demo.sshtest.Customer" table="CUSTOMER" lazy="true">
        <id name="Id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>
        <property name="cName" type="java.lang.String" access="field">
            <column name="CNAME" />
        </property>
        <set name="merchant" table="MERCHANT" cascade="save-update" order-by="ID DESC">
            <key>
                <column name="ID" />
            </key>
            <one-to-many class="com.demo.sshtest.Merchant" />
        </set>
    </class>
</hibernate-mapping>

(4)Merchant.hbm.xml “一”端映射关系配置文件

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-4-12 22:02:51 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="com.demo.sshtest.Merchant" table="MERCHANT">
        <id name="merId" type="java.lang.Integer">
            <column name="MERID" />
            <generator class="native" />
        </id>
        <property name="merName" type="java.lang.String">
            <column name="MERNAME" />
        </property>
    </class>
</hibernate-mapping>

(5)TestOne2Many.java 测试类

package com.demo.sshtest;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestOne2Many {

    //类级别检索策略:
    //①立即检索,立即加载检索方法指定的对象
    //②延迟检索,延迟加载检索方法指定的对象,在使用具体属性值时,才进行加载(这个时候会执行查询语句)

    //使用场景:
    //①如果加载对象是为了访问他的属性,则使用立即加载
    //②如果加载对象目的是为了获得他的应用,则可以使用延迟加载

    //注意事项:
    //①注意使用懒加载的时候要保证session没有关闭,否则会出现懒加载异常
    //②class的lazy属性仅对session的load()方法有效
    //③但lazy是默认或者true时,load()不会运行sql,只会代理对象实例(仅初始化其 OID 属性)
    //④在上一点的情况下,应用程序第一次访问代理类实例的非 OID 属性时, Hibernate 会初始化代理类实例(这个时候会执行查询语句)

    //步骤:
    //在映射关系配置文件中,class标签后修改lazy值
    //延迟检索/延迟加载:lazy="true"或默认情况下   :class com.demo.sshtest.Customer_$$_javassist_1 拿到的是代理对象
    //立即检索/立即加载:lazy="false"的情况下        :class com.demo.sshtest.Customer 拿到了对象


    public SessionFactory sessionFactory;
    public Session session;
    public Transaction transaction;

    @Before
    public  void init(){
        Configuration configuration = new Configuration().configure();
        ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
        System.out.println("init");
    }
    @After
    public  void destory(){
        transaction.commit();
        session.close();
        sessionFactory.close();
        System.out.println("destory");
    }

    @Test
    public void test() throws Exception{

        System.out.println("test");
        Customer customer = new Customer();
        customer.setcName("cccName");
        Merchant merchant1 = new Merchant();
        Merchant merchant2 = new Merchant();
        merchant1.setMerName("merchant1");
        merchant2.setMerName("merchant2");
        customer.getMerchant().add(merchant1);
        customer.getMerchant().add(merchant2);
        session.save(customer);
        session.save(merchant1);
        session.save(merchant2);
    }
    @Test
    public void testquery(){
        System.out.println("testquery");
        Customer customer = (Customer)session.load(Customer.class,1);
        System.out.println(customer.getClass());
        System.out.println(customer.getId());
        System.out.println(customer.getcName());
    }
}

8、检索策略的lazy、fetch、batch-size属性使用
(1)Customer.java “一”端(因为关系配置有用set)

package com.demo.sshtest;

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

public class Customer {

    public Integer Id;
    public String cName;

    public Set<Merchant>merchant = new HashSet<>();

    public Integer getId() {
        return Id;
    }
    public void setId(Integer id) {
        Id = id;
    }
    public String getcName() {
        return cName;
    }
    public void setcName(String cName) {
        this.cName = cName;
    }
    public Set<Merchant> getMerchant() {
        return merchant;
    }
    public void setMerchant(Set<Merchant> merchant) {
        this.merchant = merchant;
    }

}

(2)Merchant.java “多”端

package com.demo.sshtest;

public class Merchant {

    public Integer merId;
    public String merName;
    public Integer getMerId() {
        return merId;
    }
    public void setMerId(Integer merId) {
        this.merId = merId;
    }
    public String getMerName() {
        return merName;
    }
    public void setMerName(String merName) {
        this.merName = merName;
    }

}

(3)Customer2.hbm.xml “多”端关系映射配置文件

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-4-12 22:01:32 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="com.demo.sshtest2.Customer2" table="CUSTOMER2">
        <id name="Id" type="java.lang.Integer">
            <column name="ID" />
            <generator class="native" />
        </id>
        <property name="cName" type="java.lang.String" access="field">
            <column name="CNAME" />
        </property>

        <set name="merchant" table="MERCHANT2" inverse="true" lazy="true" batch-size="5" fetch="join">
            <key>
                <column name="ID" />
            </key>
            <one-to-many class="com.demo.sshtest2.Merchant2" />
        </set>
    </class>
</hibernate-mapping>

这里面fetch的值 按照测试需要 可以改成select、subselect或者join

(4)Merchant2.hbm.xml “一”端映射关系配置文件

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2018-4-12 22:02:51 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
    <class name="com.demo.sshtest2.Merchant2" table="MERCHANT2">
        <id name="merId" type="java.lang.Integer">
            <column name="MERID" />
            <generator class="native" />
        </id>
        <property name="merName" type="java.lang.String">
            <column name="MERNAME" />
        </property>
    </class>
</hibernate-mapping>

(5)TestOne2Many.java 测试类

package com.demo.sshtest2;

import java.util.List;

import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestOne2Many {

    //一对多和多对多的检索策略
    //set标签中对应属性用法:
    //①lazy: 主要决定 orders 集合被初始化的时机. 即到底是在加载 Customer 对象时就被初始化, 还是在程序访问 orders 集合时被初始化
    //②fetch: 取值为 “select” 或 “subselect” 时, 决定初始化 orders 的查询语句的形式;  若取值为”join”, 则决定 orders 集合被初始化的时机
    //        若把 fetch 设置为 “join”, lazy 属性将被忽略
    //③batch-size:批量检索能减少 SELECT 语句的数目, 提高延迟检索或立即检索的运行性能

    //(1)lazy:
    //1、一对多或者多对多的集合属性默认使用懒加载检索策略
    //2、可以通过设置set的lazy属性修改检索策略,默认true
    //3、set的lazy属性不建议设为false,sql语句翻倍,减慢效率
    //4、lazy还可以设为extra(增强延迟检索),该取值会尽可能延迟集合初始化时机,就是能不初始化就不初始化,直接执行sql
    //5、如果lazy是true、extra、默认的时候,要对集合的某个代理对象进行初始化,显式调用Hibernate.initialize即可

    //(2)batch-size:
    //1、是在使用懒加载(lazy="true"或者默认或者extra)情况下使用
    //2、作用:用来为延迟检索策略或立即检索策略设定批量检索的数量. 批量检索能减少 SELECT 语句的数目, 提高延迟检索或立即检索的运行性能
    //3、使用:去set那里设置batch-size的值,数值未多少,一次性初始化set集合的对象的数量就是多少

    //(3)fetch:
    //1、fetch属性值的取值是select和subselect时,决定初始化对象的时候的查询语句形式
    //2、fetch属性值的取值是join时,决定对象集合被初始化时机
    //3、set集合的fetch属性:
    //①默认为select,通过正常方式初始化set元素
    //②取值为subselect时,通过子查询方式初始化所有set集合,子查询在where子句的in出现,查询所有该端的主键(ID),lazy有效,batch-size无效
    //③取值为join时,检索对象时,才有迫切左外连接策略检查关联的对象,lazy无效(注意:Query.list()会忽略映射配置中的迫切左外连接检索策略,会用延迟加载策略)

    //一对多和多对多的检索策略
    //lazy属性和fetch属性取值对应检索策略
    //1、lazy取值可以为true、false、extra(默认true),fetch取值为select、subselect、join(默认select)
    //①lazy=true               fatch=默认                   采用延迟检索
    //②lazy=false              fatch=默认                   采用立即检索
    //③lazy=extra              fatch=默认                   采用加强延迟检索(延迟对象集合初始化时机)
    //④lazy=true/false/extra   fatch=默认                   根据lazy决定执行检索策略
    //⑤lazy=true/false/extra   fatch=subselect  根据lazy决定执行检索策略
    //⑥lazy=默认                                        fatch=join       采用迫切左外连接策略

    //多对一和一对一的检索策略
    //1、lazy取值可以为proxy、no-proxy、false(默认proxy),fetch取值可以为:select和join(默认select)
    //2、lazy取值为proxy和false分别代表采用延迟检索和立即检索
    //3、batch-size,设置在“一”端的class元素中,而不是像一对多、多对多的检索策略那样设置在set里面
    //4、如果fetch取值join时,lazy无效
    //5、lazy属性和fetch属性取值对应检索策略
    //①lazy=proxy      fetch=默认        采用延迟检索
    //②lazy=non-proxy  fetch=默认        采用无代理延迟检索(需要增强持久化类的字节码才能实现)
    //③lazy=false      fetch=默认        采用立即检索
    //④lazy=默认                   fetch=join   采用迫切左外连接策略(比立即检索用更少select语句)

    public SessionFactory sessionFactory;
    public Session session;
    public Transaction transaction;

    @Before
    public  void init(){
        Configuration configuration = new Configuration().configure();
        ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
        sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        session = sessionFactory.openSession();
        transaction = session.beginTransaction();
        System.out.println("init");
    }
    @After
    public  void destory(){
        transaction.commit();
        session.close();
        sessionFactory.close();
        System.out.println("destory");
    }

    @Test
    public void test() throws Exception{
        System.out.println("test");
        Customer2 customer = new Customer2();
        customer.setcName("cccName");
        Merchant2 merchant1 = new Merchant2();
        Merchant2 merchant2 = new Merchant2();
        merchant1.setMerName("merchant1");
        merchant2.setMerName("merchant2");
        customer.getMerchant().add(merchant1);
        customer.getMerchant().add(merchant2);
        session.save(customer);
        session.save(merchant1);
        session.save(merchant2);
    }
    @Test
    public void testquery(){
        System.out.println("testquery");
        Customer2 customer = (Customer2)session.get(Customer2.class,1);
        System.out.println(customer.getcName());
        System.out.println(customer.getMerchant().getClass());

        Merchant2 merchant2 = new Merchant2();
        merchant2.setMerId(1);
        System.out.println(customer.getMerchant().contains(merchant2));

        //如果懒加载的时候,要对集合的某个代理对象进行初始化,显式调用Hibernate.initialize即可
        Hibernate.initialize(customer.getMerchant());
    }

    @Test
    public void testBatchSize(){
        List<Customer2> customer2 = session.createQuery("FROM Customer2").list();
        System.out.println(customer2.size());
        for(Customer2 customer22 :customer2){
            //使用懒加载(lazy="true"或者默认或者extra)时,如果不设置batch-size 这里每次检查customer22.getMerchant()是不是为空的时候 ,需要查询4次
            //所以需要批量对customer22.getMerchant()对象初始化
            //去set那里设置batch-size,就可以了
            //作用:用来为延迟检索策略或立即检索策略设定批量检索的数量. 批量检索能减少 SELECT 语句的数目, 提高延迟检索或立即检索的运行性能
            if(customer22.getMerchant()!=null){
                System.out.println(customer22.getMerchant().size());
            }
        }
    }

    @Test
    public void testFetch(){
        List<Customer2> customer2 = session.createQuery("FROM Customer2").list();
        System.out.println(customer2.size());
        for(Customer2 customer22 :customer2){
            //fetch属性值的取值是select和subselect时,决定初始化对象的时候的查询语句形式
            //set集合的fetch属性:
            //1、默认为select,通过正常方式初始化set元素
            //2、取值为subselect时,通过子查询方式初始化所有set集合,子查询在where子句的in出现,查询所有该端的主键(ID),lazy有效,batch-size无效
            if(customer22.getMerchant()!=null){
                System.out.println(customer22.getMerchant().size());
            }
        }
    }

    @Test
    public void testFetch2(){
        //fetch属性值的取值是join时,决定对象集合被初始化时机
        //set集合的fetch属性:
        //1、取值为join时,检索对象时,才有迫切左外连接策略检查关联的对象(查询端的另一端)
        //2、迫切左外链接就是指:使用左外链接查询,且把集合属性进行初始化
        //3、当fetch值为join时,lazy属性会无效(注意:Query.list()会忽略映射配置中的迫切左外连接检索策略,会用延迟加载策略)
        //4、HQL查询时,忽略fetch=join的取值
        Customer2 customer2 = (Customer2)session.get(Customer2.class, 1);
        System.out.println(customer2.getMerchant().size());
    }
}

9、hibernate.cfg.xml hibernate配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>

        <!-- 配置连接数据库基本信息 -->
        <property name="connection.username">root</property>
        <property name="connection.password"></property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <!-- localhost是地址,如果用默认可以不写localhost,hebernateTEST是数据库名 -->
        <property name="connection.url">jdbc:mysql://localhost/hebernateTEST</property>

        <!-- 配置hibernate基本信息-->
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

        <!-- 执行操作室是否在控制台打印sql -->
        <property name="show_sql">true</property>
        <!-- 是否对sql格式化 -->
        <property name="format_sql">true</property>

        <!-- 指定自动生成数据表的策略 -->
        <property name="hbm2ddl.auto">update</property>

        <!-- 设置 Hibernate 的事务隔离级别 -->
        <property name="connection.isolation">2</property>

        <!-- 设置调用delete()时,OID变成null -->
        <property name="hibernate.use_identifier_rollback">true</property>

        <!--C3P0 数据库连接池-->
        <property name="hibernate.c3p0.max_size">10</property>
        <property name="hibernate.c3p0.min_size">5</property>
        <property name="hibernate.c3p0.timeout">2000</property>
        <property name="hibernate.c3p0.max_statements">10</property>
        <property name="hibernate.c3p0.idle_test_period">2000</property>
        <property name="hibernate.c3p0.acquire_increment">2</property>

        <!--设定JDBC的statement读取数据-->
        <property name="hibernate.jdbc.fetch_size">100</property>
        <property name="hibernate.jdbc.batch_size">50</property>

        <!-- 指定关联的 *.hbm.xml文件(目录结构) 每个.hbm.xml对应一个数据表-->
        <mapping resource="com/demo/sshtest/Customer.hbm.xml"/>
        <mapping resource="com/demo/sshtest/Merchant.hbm.xml"/>
        <mapping resource="com/demo/sshtest2/Customer2.hbm.xml"/>
        <mapping resource="com/demo/sshtest2/Merchant2.hbm.xml"/>

    </session-factory>
</hibernate-configuration>

9、注意事项:
(1)注意多对一和一对一的时候lazy可选的值比一对多和多对多的时候多了proxy和non-proxy
(2)其实没什么需要在这里写的,用法和注意事项都写到注释里面去了,注意测试类的注释就好了

10、项目目录
项目目录

11、demo
https://download.csdn.net/download/qq_22778717/10359603

猜你喜欢

转载自blog.csdn.net/qq_22778717/article/details/80002278
今日推荐