hibernate的延迟加载

Posted 努力奋斗吧

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hibernate的延迟加载相关的知识,希望对你有一定的参考价值。

 

延迟加载:延迟加载(lazy load懒加载)是当在真正需要数据时,才执行SQL语句进行查询,避免了无谓的性能开销。

延迟加载分类:

 01.类级别的查询策略

 02.一对多和多对多关联的查询策略

 03.多对一关联的查询策略

 

类级别的查询策略

1.类级别可选的检索策略包括立即检索延迟检索默认为延迟检索

    1.1立即检索:立即加载检索方法指定的对象,立即发送SQL

    1.2 延迟检索:延迟加载检索方法制定的对象.在使用具体的属性时,再进行加载,才发送SQL

 2.无论<class>元素的lazy属性是true还是falseSessionget()方法及Querylist()方法在类级别总是使用立即检索策略

 3.<class>元素的lazy属性为true或默认值,Sessionload()方法不会执行查询数据库表的SELECT语句,仅返回代理类对象的实例,该代理类实例有如下特征:

 3.1 Hibernate在运行时采用CGLIB工具动态生成
 3.2 Hibernate创建代理类实例时,仅初始化其OID属性
 3.3在应用程序第一次访问代理类实例的非OID属性时,Hibernate会初始化代理类实例

    3.4注意:类级别检索策略仅适用于load()方法

 

 

1.创建持久化类

public class Student {
    private int id;
    private String  name;
    private int age;
    private String address;
    private String phone;

    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 int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}

 

2.创建Student.hbm.xml配置文件

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 映射文件开始 -->
<hibernate-mapping package="cn.day05lazy.entity">
    <!--表名称-->
    <class name="Student" table="STUDENT" schema="root" lazy="true">
        <!--列名-->
       <id name="id" column="ID">
           <!--主键生成的策略  native:自动生成主键字段-->
           <generator class="native"></generator>
       </id>
        <property name="name" column="NAME"></property>
        <property name="age" column="AGE"></property>
        <property name="address" column="ADDRESS"></property>
        <property name="phone" column="PHONE"></property>
    </class>
</hibernate-mapping>

 

3.创建hibernate.cfg.xml大配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- 指定数据库所用到的驱动 -->
        <property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
        <!-- 指定数据库链接的url,hibernate链接的数据库名 -->
        <property name="connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property>
        <!-- 指定连接数据库的用户名 -->
        <property name="connection.username">root</property>
        <!-- 指定连接数据库的用户口令 -->
        <property name="connection.password">root</property>
        <!-- Enable Hibernate\'s automatic session context management -->
        <property name="current_session_context_class">thread</property>
        <!--格式化sql -->
        <property name="format_sql ">true</property>
        <!-- 打印sql 控制台-->
        <property name="show_sql">true</property>
        <!-- 指定数据库方言 -->
        <property name="dialect">org.hibernate.dialect.Oracle10gDialect</property>
        <!-- 根据需要自动创建数据库表 -->
        <property name="hbm2ddl.auto">update</property>
        <!--延迟加载-->
        <mapping resource="cn/day05lazy/entity/Student.hbm.xml"></mapping>
    </session-factory>
</hibernate-configuration>

Lazy设置为true

Load()方法测试结果:

@Test
public void test(){
    Session session = HibernateUtil.getSession();
    Student load = session.load(Student.class, 1);
}

 

 

Get()方法测试结果:

//类级别延迟加载
@Test
public void test(){
    Session session = HibernateUtil.getSession();
    Student load = session.get(Student.class, 1);
}

 

 

 

如果将lazy设置为false,则load()方法的延迟加载取消

//类级别延迟加载
@Test
public void test(){
    Session session = HibernateUtil.getSession();
    Student load = session.load(Student.class, 1);
}

 

 

一对多和多对多关联的查询策略

在映射文件中,用<set>元素来配置一对多关联及多对多关联关系。<set>元素有lazyfetch属性

-lazy:主要决定Emps集合被初始化的时机。即到底是在加载Dept对象时就被初始化,还是在程序访问Emps集合时被初始化

 

01.一对多或者多对多检索策略由lazyfetch共同确定

    Lazy:决定关联对象初始化时机

    Fetch:决定SQL语句构建形式

02.fetch取值

    Join:迫切左外连接

    Select:多条简单SQL(默认值)

    Subselect:子查询

03.fetchlazy组合

解析:fetch=”join” lazy会被忽略,迫切左外连接的立即检索

        Fetch=”select” lazy=”false”  多条简单SQL立即检索

        Fetch=”select” lazy=”true”  多条语句延迟检索

        Fetch=”select” lazy=”extra”  多条语句及其懒惰检索

        Fetch=”subselect” lazy=”false”  子查询立即检索

        Fetch=”subselect” lazy=”true”  子查询延迟检索

        Fetch=”subselect” lazy=”extra”  子查询及其懒惰检索

Extra:极其懒惰,只有访问集合对象的属性时才会加载,访问集合本身的属性时(例如,集合大小,生成count),不会立即加载。

注意:querylist()会忽略映射文件配置的左外连接查询,此时lazy属性重新生效。

一对多延迟加载测试

Lazy设置为true

核心代码:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 映射文件开始 -->
<hibernate-mapping package="cn.day04mapping.onetomany.entity">
    <!--表名称-->
    <class name="Dept" table="DEPT" schema="root">
        <!--列名-->
       <id name="deptid" column="DEPTID">
           <!--主键生成的策略  native:自动生成主键字段-->
           <generator class="native"></generator>
       </id>
     <property name="deptname" column="DEPTNAME"></property>
        <!--植入set 标签  save-update 保存数据   inverse 消除多余的update语句-->
        <set name="emps" cascade="save-update"  inverse="true" order-by="empno desc" lazy="true">
            <!--多的一方表的外键列-->
            <key column="deptno"></key>
            <one-to-many class="Emp"></one-to-many>
        </set>
    </class>
</hibernate-mapping>

 

//一对多
@Test
public void test01(){
    Session session = cn.day04mapping.onetomany.util.HibernateUtil.getSession();
    Dept dept = session.get(Dept.class, 24);
    //Set<Emp> emps = dept.getEmps();
}

 

 

Lazy设置为false

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 映射文件开始 -->
<hibernate-mapping package="cn.day04mapping.onetomany.entity">
    <!--表名称-->
    <class name="Dept" table="DEPT" schema="root">
        <!--列名-->
       <id name="deptid" column="DEPTID">
           <!--主键生成的策略  native:自动生成主键字段-->
           <generator class="native"></generator>
       </id>
     <property name="deptname" column="DEPTNAME"></property>
        <!--植入set 标签  save-update 保存数据   inverse 消除多余的update语句-->
        <set name="emps" cascade="save-update"  inverse="true" order-by="empno desc" lazy="false">
            <!--多的一方表的外键列-->
            <key column="deptno"></key>
            <one-to-many class="Emp"></one-to-many>
        </set>
    </class>
</hibernate-mapping>

 

//一对多
@Test
public void test01(){
    Session session = cn.day04mapping.onetomany.util.HibernateUtil.getSession();
    Dept dept = session.get(Dept.class, 24);
    //Set<Emp> emps = dept.getEmps();
}

 

 

Lazy设置为extra

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 映射文件开始 -->
<hibernate-mapping package="cn.day04mapping.onetomany.entity">
    <!--表名称-->
    <class name="Dept" table="DEPT" schema="root">
        <!--列名-->
       <id name="deptid" column="DEPTID">
           <!--主键生成的策略  native:自动生成主键字段-->
           <generator class="native"></generator>
       </id>
     <property name="deptname" column="DEPTNAME"></property>
        <!--植入set 标签  save-update 保存数据   inverse 消除多余的update语句-->
        <set name="emps" cascade="save-update"  inverse="true" order-by="empno desc" lazy="extra">
            <!--多的一方表的外键列-->
            <key column="deptno"></key>
            <one-to-many class="Emp"></one-to-many>
        </set>
    </class>
</hibernate-mapping>

 

 //一对多
@Test
public void test01(){
    Session session = cn.day04mapping.onetomany.util.HibernateUtil.getSession();
    Dept dept = session.get(Dept.class, 24);
    //Set<Emp> emps = dept.getEmps();
}

 

//一对多
@Test
public void test01(){
    Session session = cn.day04mapping.onetomany.util.HibernateUtil.getSession();
    Dept dept = session.get(Dept.class, 24);
    Set<Emp> emps = dept.getEmps();
    emps.size();
}

 

 

 

 多对一关联的查询策略

 

Lazy设置为false

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- 映射文件开始 -->
<hibernate-mapping package="cn.day04mapping.manytoone.entity">
    <!--name:表名称  schema 操作数据库的用户名-->
    <class name="Emp" table="EMP" schema="root">
        <!--列名-->
       <id name="empno" column="EMPNO">
           <!--主键生成的策略  native:自动生成主键字段-->
           <generator class="native"></generator>
       </id>
     <property name="ename" column="ENAME"></property>
        <!--多对一 单向关联
        员工是多的一方
        name:Emp中植入一方的属性名称
        column;数据库中外键列的值
        class:植入一方的属性的类型
        -->
        <many-to-one name="dept" column="deptno" class="Dept" lazy="false"></many-to-one>
    </class>
</hibernate-mapping>

 

 

//多对一
@Test
public void test03(){
    Session session = cn.day04mapping.manytoone.util.HibernateUtil.getSession();
    cn.day04mapping.manytoone.entity.Emp emp = session.get(cn.day04mapping.manytoone.entity.Emp.class, 1);
}

 

 

 

 

Lazy设置为proxy

<?xml version="1.0"?>
        <!DOCTYPE hibernate-mapping PUBLIC
                "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
        <!-- 映射文件开始 -->
<hibernate-mapping package="cn.day04mapping.manytoone.entity">
<!--name:表名称  schema 操作数据库的用户名-->
<class name="Emp" table="EMP" schema="root">
    <!--列名-->
    <id name="empno" column="EMPNO">
        <!--主键生成的策略  native:自动生成主键字段-->
        <generator class="native"></generator>
    </id>
    <property name="ename" column="ENAME"></property>
    <!--多对一 单向关联
    员工是多的一方
    name:Emp中植入一方的属性名称
    column;数据库中外键列的值
    class:植入一方的属性的类型
    -->
    <many-to-one name="dept" column="deptno" class="Dept" lazy="proxy"></many-to-one>
</class>
</hibernate-mapping>

 

//多对一
@Test
public void test03(){
    Session session = cn.day04mapping.manytoone.util.HibernateUtil.getSession();
    cn.day04mapping.manytoone.entity.Emp emp = session.get(cn.day04mapping.manytoone.entity.Emp.class, 1);
}

 

 

 

 

Lazy设置为no-proxy

<?xml version="1.0"?>
        <!DOCTYPE hibernate-mapping PUBLIC
                "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
                "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
        <!-- 映射文件开始 -->
<hibernate-mapping package="cn.day04mapping.manytoone.entity">
<!--name:表名称  schema 操作数据库的用户名-->
<class name="Emp" table="EMP" schema="root">
    <!--列名-->
    <id name="empno" column="EMPNO">
        <!--主键生成的策略  native:自动生成主键字段-->
        <generator class="native"></generator>
    </id>
    <property name="ename" column="ENAME"></property>
    <!--多对一 单向关联
    员工是多的一方
    name:Emp中植入一方的属性名称
    column;数据库中外键列的值
    class:植入一方的属性的类型
    -->
    <many-to-one name="dept" column="deptno" class="Dept" lazy="no-proxy"></many-to-one>
</class>
</hibernate-mapping>

 

 

//多对一
@Test
public void test03(){
    Session session = cn.day04mapping.manytoone.util.HibernateUtil.getSession();
    cn.day04mapping.manytoone.entity.Emp emp = session.get(cn.day04mapping.manytoone.entity.Emp.class, 1);
   // emp.getDept();
}

 

 

 有关延迟加载就讲到这里。

 

以上是关于hibernate的延迟加载的主要内容,如果未能解决你的问题,请参考以下文章

hibernate延迟加载

hibernate 延迟加载

JavaWeb系列——Hibernate——延迟加载(转)

hibernate 延迟加载

Hibernate延迟加载Lazy

Hibernate延迟加载Lazy