10.hibernate的lazy策略

提纲:

  • lazy的概念和为什么
  • 什么时候用lazy
    • 当前实体类
    • 与当前实体类关联的实体类
      • 关联多个实体:一对多,多对多
      • 关联单个实体:一对一,多对一
  • 各标签上的lazy取值
  • 多对多测试
  • 一对一测试

lazy的概念和为什么

Hibernate 的延迟加载(lazy load)是一个被广泛使用的技术。这种延迟加载保证了应用只有在需要时才去数据库中抓取相应的记录。通过延迟加载技术可以避免过多、过早地加载数据表里的数据,从而降低应用的内存开销。Hibernate 的延迟加载本质上就是代理模式的应用,当程序通过 Hibernate 装载一个实体时,默认情况下,Hibernate 并不会立即抓取它的集合属性、关联实体所以对应的记录,而是通过生成一个代理来表示这些集合属性、关联实体,这就是代理模式应用带来的优势。

什么时候用lazy

主要是两个地方使用:

  1. 当前实体类加载
  2. 和当前实体类关联的实体类或者实体类集合加载时

第一个种容易理解,就是一个实体类,从数据库中查询了一条记录,在还没有实际使用的时候,不会真正的去数据库查询,采用代理假装已经查到了。
第二种是当前实体类延迟已经设置好,那和当前实体类关联的实体类或者实体类集合如何加载呢,如果关联的实体类集合数据量比较巨大,总不能一次性全部加载吧,所以也需要延迟加载。

所以总结出来就是,看当前用的实体类(当前也可能是实体类集合,多条记录嘛),再关注一下和这个实体类关联的那些实体类或实体类集合。

各标签上的lazy取值

上面已经讲解了主要的应用场景,那具体怎么设置呢,也就是当前实体类和关联实体类(集合)的延迟具体怎么设置?!

标签 取值范围 解决问题
class true/false 当前实体类
set/list true/false/extra 关联实体类(集合)
one-to-one/many-to-one false/proxy/no-proxy 关联实体类(集合)

property标签也可以设置lazy属性,但是不怎么用,我也不会用!

多对多测试

实体类classes.java

    package entity;
    
    import java.util.Set;
    
    /**
     * 这里还是用classes做测试,多对多,也就是一个学生可以在多个班上课,一个班可以有多个学生
     * @author arkulo
     *
     */
    public class Classes {
        private int id;
        private String className;
        private Set<Student> student;
        
        
        
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getClassName() {
            return className;
        }
        public void setClassName(String className) {
            this.className = className;
        }
        public Set<Student> getStudent() {
            return student;
        }
        public void setStudent(Set<Student> student) {
            this.student = student;
        }
    }

    <?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="entity">
        <class name="Classes" dynamic-update="true" lazy="false" >
            <id name="id">
                <generator class="native"/>
            </id>
            <property name="className" />
            <set name="student" table="_relation_classes_student" lazy="false">
            <!-- 这里维护一张中间表,student_id关联student表,classes_id关联classes表 -->
                <key column="classes_id"></key>
                <many-to-many class="Student" column="student_id"></many-to-many>
            </set>
        </class>    
    </hibernate-mapping>

实体类student.java

    package entity;
    
    import java.util.Set;
    
    public class Student {
        private int id;
        private String name;
        private Set classes;
        
        
        public Set getClasses() {
            return classes;
        }
        public void setClasses(Set classes) {
            this.classes = classes;
        }
        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;
        }
    }

    <?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="entity">
        <class name="Student" dynamic-update="true">
            <id name="id">
                <generator class="native"/>
            </id>
            <property name="name" />
            <set name="classes">
                <key column="student_id"></key>
                <many-to-many class="Classes" column="classes_id"></many-to-many>
            </set>
        </class>    
    </hibernate-mapping>

单元测试:

    package entity;
    
    import java.util.HashSet;
    import java.util.Iterator;
    import java.util.Set;
    
    import org.hibernate.classic.Session;
    
    import junit.framework.TestCase;
    import util.hibernateUtil;
    
    /**
     * 测试目的:
     * 这里测试的是关联实体多对多的情况,就是查看是否能够lazy加载
     * 
     * 结果:
     * 不同的标签(class,set)设置lazy为false,会对实体类,或者实体类相关的实体或实体集合产生影响
     * @author arkulo
     *
     */
    
    public class testLazy extends TestCase {
    //  数据准备
        public void test1() {
            Session session = null;
    
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
    //          先插入3条学生记录,然后插入班级记录,又插入三条关系表记录
                
                Student st1 = new Student();
                st1.setName("张三");
                Student st2 = new Student();
                st2.setName("李四");          
                Student st3 = new Student();
                st3.setName("王五");  
                session.save(st1);
                session.save(st2);
                session.save(st3);
    
                Classes cl = new Classes();
                cl.setClassName("音乐班");
                Classes cl1 = new Classes();
                cl1.setClassName("美术班");
                Classes cl2 = new Classes();
                cl2.setClassName("跆拳道班");       
                
    //          上音乐班的学生
                Set<Student> jihe = new HashSet();
                jihe.add(st1);
                jihe.add(st2);
                cl.setStudent(jihe);
    //          上美术班的同学
                Set<Student> jihe1 = new HashSet();
                jihe1.add(st2);
                jihe1.add(st3);
                cl1.setStudent(jihe1);          
    //          上跆拳道班的学生
                Set<Student> jihe2 = new HashSet();
                jihe2.add(st1);
                jihe2.add(st3);
                cl2.setStudent(jihe2);                  
    
                            
                session.save(cl);
                session.save(cl1);
                session.save(cl2);
    
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            } finally {
                hibernateUtil.closeSession(session);
            }
        }
        
        
    //  这里是查询操作
        public void test2()
        {
            test1();
            System.out.println("------------------------------");
            Session session = null;
    
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction(); 
                
    //          当前实体类是Classes,class标签上使用lazy的默认设置(true),这里load使用了延时加载
    //          如果set集合设置lazy为false,class的lazy为true,执行到load函数,当前实体Classes延迟,但是下句打印班级名称时,
    //          是将classes和student一起查出来,共发出两个sql语句
                Classes cl = (Classes)session.load(Classes.class, 1);
                System.out.println("班级名称:"+cl.getClassName());
    
    //          set集合lazy设置为true,这是关联多个实体类,在下面从cl中获取student是没有发出sql语句的
    //          set集合lazy设置为false,在上面输出班级名称时,就一起发出sql查询了,没有执行延迟操作
                Set<Student> sts = cl.getStudent();
    //          在下面的iterator操作中发出了sql语句,延迟加载
                for(Iterator<Student> it = sts.iterator();it.hasNext();)
                {
                    Student student = it.next();
                    System.out.println("学生姓名:"+student.getName());
                }
                
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            } finally {
                hibernateUtil.closeSession(session);
            }       
        }
        
    
    }

一对一测试

实体类User.java

    package entity;
    
    import java.util.Date;
    
    public class User {
        private int id;
        private String userName;
        private String passWd;
        private Date addtime;
        private Group group;
        
        public Date getAddtime() {
            return addtime;
        }
    
        public void setAddtime(Date addtime) {
            this.addtime = addtime;
        }
    
        public User(){}
    
    
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getUserName() {
            return userName;
        }
    
        public void setUserName(String userName) {
            this.userName = userName;
        }
    
        public String getPassWd() {
            return passWd;
        }
    
        public void setPassWd(String passWd) {
            this.passWd = passWd;
        }
    
        public Group getGroup() {
            return group;
        }
    
        public void setGroup(Group group) {
            this.group = group;
        }
        
        
    }

    <?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="entity.User" lazy="false">
            <id name="id">
                <!-- 如果是uuid的话,需要id配置为String类型 -->
                <!--  <generator class="uuid"/>-->
                <generator class="identity" />
            </id>
            <property name="userName" />        
            <property name="passWd" />
            <property name="addtime" type="time" />
            <many-to-one name="group" column="group_id" class="entity.Group" lazy="proxy" />
        </class>    
    </hibernate-mapping>

实体类Group.java

    package entity;
    
    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;
        }
    }

    <?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="entity.Group" table="_group">
            <id name="id">
                <generator class="identity" />
            </id>
            <property name="name" />        
        </class>    
    </hibernate-mapping>

单元测试:

    package entity;
    
    import java.util.Date;
    
    import org.hibernate.SessionFactory;
    import org.hibernate.classic.Session;
    
    import junit.framework.TestCase;
    import util.hibernateUtil;
    
    /**
     * 测试目的:
     * 这里是测试实体类关联另外一个实体类(一对一,多对一)的情况下,设置lazy
     * 其实就是在many-to-one/one-to-one标签上设置lazy属性,然后查看延迟效果
     * 
     * 这里设定的主实体类是user,也就是在user对应一个group
     * @author arkulo
     *
     */
    
    public class UserTest extends TestCase {
    
        /**
         * 初始化数据写入,测试普通级联写入数据,和数据读取
         */
        public void test1(){
            Session session = null;
            
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
                
                Group gp1 = new Group();
                gp1.setName("产品组");
                session.save(gp1);
                
                User user1 = new User();
                user1.setUserName("王蕊");
                user1.setPassWd("123456");
                user1.setGroup(gp1);
                user1.setAddtime(new Date());
                
                session.save(user1);
                
                System.out.println("--------------------------------");
    //          在一个session中,下面的代码会直接利用一级缓存
                User userTmp = (User)session.load(User.class, 1);
                
                System.out.println("用户名:"+userTmp.getUserName());
                System.out.println("组名:"+userTmp.getGroup().getName());
                
                
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            }finally{
                hibernateUtil.closeSession(session);
            }       
        }
        
    //  读取数据,查看延迟加载情况
        public void test2(){
            test1();
            System.out.println("--------------------------------");
            Session session = null;
            
            try {
                session = hibernateUtil.getSession();
                session.beginTransaction();
    //          class上的lazy设置不用说明,true就延迟,false就立刻
                
                User userTmp = (User)session.load(User.class, 1);
                System.out.println("用户名:"+userTmp.getUserName());
    //          many-to-one标签上lazy为true,延迟加载,如果为false,会在上面load函数的时候多发出一条查询group的sql
                Group g = userTmp.getGroup();       
                System.out.println("组名:"+g.getName());
                
                
                session.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                session.getTransaction().rollback();
            }finally{
                hibernateUtil.closeSession(session);
            }       
        }       
        
        
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容