9.Lazy策略(hibernate笔记)

一、简介

  • 延迟加载就是我们真正使用某个对象的时候,这个对象才会被创建出来。而在hibernate中的意思就是只有我们真正需要使用某个对象的时候,才会去查询。采用第三方的一个库cglab,生成代理类。和jdk的动态代理的区别是cglab能对类进行代理(继承原先的类生成一个子类,子类作为代理类),而jdk的动态代理只能对实现了接口的类进行代理。
  • hibernate的lazy策略可以使用在:

    • <class>标签上,可以取值:true、false,默认是true,打开。
    • <property>标签上,可以取值true、false,默认是true打开,使用较少。需要类增强工具(不讲)。
    • <set><list>标签上,可以取值true、false、extra
    • <one_to_one><many_to_one>标签中,单端关联上,可以取值:false、proxy、noproxy
  • 代理的概念:只有真正使用该对象时才会创建,对于hibernate来说就是只有真正使用的时候才会发出sql。注意:lazy和Session的生命周期一致。

二、用在class标签上(工程hibernate_lazy4class

实体类(Group.java

package cn.itcast.hibernate;
public class Group {
    private int id ;
    private String name ;
    
    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;
    }
}

Group.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">
<hibernate-mapping>
    <class name="cn.itcast.hibernate.Group" table="_group">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
    </class>
</hibernate-mapping>

先在数据库中存入一些数据:
InitData.java

package cn.itcast.hibernate;
import org.hibernate.Session;
public class InitData {

    public static void main(String[] args) {
        Session session = null ;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            Group group = new Group();
            group.setName("高二班");
            session.save(group);
            session.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }
}

测试:
ClassLazyTest.java

package cn.itcast.hibernate;
import org.hibernate.Session;
import org.junit.Test;
/*
 *在测试的时候有个条件是:设置<class>标签上的lazy=true,也就是默认配置 
 * */
public class ClassLazyTest {
    
    @Test
    public void testLoad1(){
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            //不会发sql,因为没有真正用到
            Group gorup = (Group) session.load(Group.class, 1);
            
            //这里是不会发sql的,因为主键在上面已经给出了
            System.out.println("group.id = " + gorup.getId());
            //这里是要发sql的,因为需要用到
            System.out.println("group.name = " + gorup.getName());
            session.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }
    
    @Test
    public void testLoad2(){
        Session session = null;
        Group group = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            group = (Group) session.load(Group.class, 1);
            System.out.println("group.id = " + group.getId());
            
            System.out.println("group.name = " + group.getName());
            session.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally{
            HibernateUtils.closeSession(session);
            
        }
        //不能正确执行,抛出异常,因为session已经关闭,hibernate支持lazy策略只有在session打开状态下有效
        System.out.println("group.name = " + group.getName());
    }
}

三、用在集合标签上(工程hibernate_lazy4collection

这里我们使用一对多双向关联的例子。
实体类:
Student.java

private int id ;
private String name ;
private Classes classes;

Classes.java

private int id ;
private String name ;
private Set students;

配置:
Student.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">
<hibernate-mapping>
    <class name="cn.itcast.hibernate.Student" table="_student">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <many-to-one name="classes" column="classesid"/>
    </class>
</hibernate-mapping>

Classes.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">
<hibernate-mapping package="cn.itcast.hibernate">
    <class name="Classes" table="_classes">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
        <set name="students" inverse="true" cascade="all" >
            <key column="classesid"/>
            <one-to-many class="Student"/>
        </set>
    </class>
</hibernate-mapping>

首先我们需要在数据库中存入几条数据。
测试:

  • 1.保持lazy默认
    CollectionLazyTest1.java
package cn.itcast.hibernate;
import java.util.Iterator;
import java.util.Set;
import org.hibernate.Session;
import org.junit.Test;
/*保持lazy默认*/
public class CollectionLazyTest1 {
    
    @Test
    public void testLoad1(){
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            //不会发出sql
            Classes classes = (Classes) session.load(Classes.class, 1);
            
            //会发出sql
            System.out.println("classes.name = " + classes.getName());
            
            //不会发出sql
            Set students = classes.getStudents();
            
            //会发出sql
            for (Iterator iter=students.iterator(); iter.hasNext();) {
                Student student = (Student)iter.next();
                System.out.println("student.name=" + student.getName());
            }
            session.getTransaction().commit();
            
        } catch (Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }
    @Test
    public void testLoad2() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            //不会发出sql
            Classes classes = (Classes)session.load(Classes.class, 1);
            
            //会发出sql
            System.out.println("classes.name=" + classes.getName());
            
            //不会发出sql
            Set students = classes.getStudents();
            
            //会发出sql,发出查询全部数据的sql
            System.out.println("student.count=" + students.size());
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }   
}

说明:这里我们可以看到在默认情况下,不管是集合还是普通属性都是支持延迟加载的。

  • 2.设置<class>标签上的lazy=false
    CellectionlazyTest2.java
package cn.itcast.hibernate;
import java.util.Iterator;
import java.util.Set;
import junit.framework.TestCase;
import org.hibernate.Session;
/**
 * 设置<class>标签上的lazy=false
 * @author Administrator
 *
 */
public class CellectionlazyTest2 extends TestCase {

    public void testLoad1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            //会发出sql
            Classes classes = (Classes)session.load(Classes.class, 1);
            
            //不会发出sql
            System.out.println("classes.name=" + classes.getName());
            
            //不会发出sql
            Set students = classes.getStudents();
            
            //会发出sql
            for (Iterator iter=students.iterator(); iter.hasNext();) {
                Student student = (Student)iter.next();
                System.out.println("student.name=" + student.getName());
            }
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }   
}

说明:看以看到,当我们将class标签上的lazy设置为false的时候,对于普通属性就不支持延迟加载了,但是对于集合来说,还是支持延迟加载的,这说明,class上的lazy对于集合是没有影响的。

  • 3.设置集合上的lazy=false,其它默认
    CellectionlazyTest3.java
package cn.itcast.hibernate;
import java.util.Iterator;
import java.util.Set;
import junit.framework.TestCase;
import org.hibernate.Session;
/**
 * 设置集合上的lazy=false,其它默认
 *
 */
public class CellectionlazyTest3 extends TestCase {

    public void testLoad1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            //不会发出sql
            Classes classes = (Classes)session.load(Classes.class, 1);
            
            //会发出sql,会发出两条sql分别加载Classes和Student
            System.out.println("classes.name=" + classes.getName());
            
            //不会发出sql
            Set students = classes.getStudents();
            
            //不会发出sql
            for (Iterator iter=students.iterator(); iter.hasNext();) {
                Student student = (Student)iter.next();
                System.out.println("student.name=" + student.getName());
            }
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }   
    
    public void testLoad2() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            //不会发出sql
            Classes classes = (Classes)session.load(Classes.class, 1);
            
            //会发出sql,会发出两条sql分别加载Classes和Count
            System.out.println("classes.name=" + classes.getName());
            
            //不会发出sql
            Set students = classes.getStudents();
            
            //不会发出sql
            System.out.println("student.count=" + students.size());
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }       
}

说明:由于将集合的lazy设置为false,则集合不支持延迟加载,那么在使用到Classes的时候就会将查询集合的sql语句也发出去。而在之后的操作中不再发送sql语句。但是在查询集合中元素个数的时候不是发送的count语句,而是直接将集合整体查出来,再统计。

  • 4.设置集合上的lazy=extra,其它默认
    CellectionlazyTest4.java
package cn.itcast.hibernate;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import junit.framework.TestCase;
import org.hibernate.Session;
/**
 * 设置集合上的lazy=extra,其它默认
 * @author Administrator
 */
public class CellectionlazyTest4 extends TestCase {

    public void testLoad1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            //不会发出sql
            Classes classes = (Classes)session.load(Classes.class, 1);
            
            //会发出sql
            System.out.println("classes.name=" + classes.getName());
            
            //不会发出sql
            Set students = classes.getStudents();
            
            //会发出sql
            for (Iterator iter=students.iterator(); iter.hasNext();) {
                Student student = (Student)iter.next();
                System.out.println("student.name=" + student.getName());
            }
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }   
    
    public void testLoad2() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            //不会发出sql
            Classes classes = (Classes)session.load(Classes.class, 1);
            
            //会发出sql
            System.out.println("classes.name=" + classes.getName());
            
            //不会发出sql
            Set students = classes.getStudents();
            //会发出sql,发出一条比较智能的sql
            System.out.println("student.count=" + students.size());
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }       
}

说明:对于直接查询出集合对象,和lazy为true的情况是一样的,是在使用的时候才会发出,但是对于查询集合中元素的个数则和上个例子不一样了,这里是发送的count语句,效率会比较高,所以在实际开发中一般使用此属性。

四、用在单端关联上(工程hibernate_lazy4single_end

单端关联有<one-to-one>和<many-to-one>,两者比较类似,这里我们使用后者作为例子。在单端关联上的lazy策略可以取值为:false、proxy、noproxy。

相关实体类:
Group.java

private int id; 
private String name;

User.java

private int id; 
private String name;
private Group group;

相关配置:
Group.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">
<hibernate-mapping package="cn.itcast.hibernate">
    <class name="Group" table="_group">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
    </class>
</hibernate-mapping>

User.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">
<hibernate-mapping package="cn.itcast.hibernate">
    <class name="User" table="_user" lazy="false">
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name"/>
         <many-to-one name="group" column="groupid"/>
    </class>
</hibernate-mapping>

先想数据库中存入一些数据:
InitData.java

package cn.itcast.hibernate;
import org.hibernate.Session;
public class InitData {

    public static void main(String[] args) {
        Session session = null ;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Group group = new Group();
            group.setName("高一班");
            session.save(group);
            
            User user1 = new User();
            user1.setName("张三");
            user1.setGroup(group);
            
            User user2 = new User();
            user2.setName("李四");
            user2.setGroup(group);
            
            session.save(user1);
            session.save(user2);
            
            session.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally{
            HibernateUtils.closeSession(session);
        }
    }
}

测试:

  • 1.<many-to-one>的lazy保持默认,即proxy。
    SingleEndTest1.java
package cn.itcast.hibernate;
import org.hibernate.Session;
import org.junit.Test;
/**
 * 所有lazy属性默认
 */
public class SingleEndTest1{
    @Test
    public void testLoad1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            //不会发出sql
            User user = (User)session.load(User.class, 1);
            
            //会发出sql
            System.out.println("user.name=" + user.getName());
            
            //不会发出sql
            Group group = user.getGroup();
            
            //会发出sql
            System.out.println("group.name=" + group.getName());
            
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }   
}

说明:可以看到这里的情况和集合的lazy策略一样,都是在使用的时候才发出sql语句。

  • 2.将<many-to-one>中的lazy设置为false,其它默认
    SingleEndTest2.java
package cn.itcast.hibernate;
import org.hibernate.Session;
import org.junit.Test;
import junit.framework.TestCase;
/**
 * 将<many-to-one>中的lazy设置为false,其它默认
 */
public class SingleEndTest2{
    @Test
    public void testLoad1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            //不会发出sql
            User user = (User)session.load(User.class, 1);
            
            //会发出sql,发出两条sql分别加载User和Group
            System.out.println("user.name=" + user.getName());
            
            //不会发出sql
            Group group = user.getGroup();
            
            //不会发出sql
            System.out.println("group.name=" + group.getName());
            
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }       
}

说明:此时不支持延迟加载了,即在使用User的时候就会将Group查询出来。

  • 3.<class>标签上的lazy=false,其它默认
    SingleEndTest3.java
package cn.itcast.hibernate;
import org.hibernate.Session;
import org.junit.Test;
/**
 * <class>标签上的lazy=false,其它默认
 */
public class SingleEndTest3  {
    
    @Test
    public void testLoad1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            //会发出sql
            User user = (User)session.load(User.class, 1);
            
            //不会发出sql
            System.out.println("user.name=" + user.getName());
            
            //不会发出sql
            Group group = user.getGroup();
            
            //会发出sql
            System.out.println("group.name=" + group.getName());
            
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }       
}

说明:将普通属性的lazy设置为false对单端关联没有影响,单端关联的lazy策略此时还是proxy。对于noproxy用的不多,这里不再说明。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,621评论 18 399
  • 一. Java基础部分.................................................
    wy_sure阅读 3,810评论 0 11
  • 本文包括:1、Hibernate的持久化类2、Hibernate 持久化对象的三个状态(难点)3、Hibernat...
    廖少少阅读 1,449评论 0 13
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,649评论 18 139
  • 学霸的体质并不是与生俱来的,更多的是后天养成的。从强迫到习惯到最后深入骨髓。就像我们知道的那句话,腹有诗书气自华。...
    七月妮安阅读 86,083评论 947 5,627