通过一道面试题来引入Hibernate之懒加载

前言

先来看看面试题:
Hibernate中get和load方法的区别?
答:相同点:都是通过主键查询的方法。session.get(User.class,1);session.load(User.class,1);
不同点:
get: 及时加载,只要调用get方法立刻向数据库查询,,执行sql语句。
load:默认使用懒加载,当用到数据的时候才向数据库查询。 相当于做了一层优化。

懒加载:(lazy)

概念:当用到数据的时候才向数据库查询,这就是hibernate的懒加载特性。
目的:提供程序执行效率!

在配置文件中设置lazy 值:
true 默认情况下使用懒加载
false 关闭懒加载

extra (在集合数据懒加载时候提升效率)
在真正使用数据的时候才向数据库发送查询的sql;
如果调用集合的size()/isEmpty()方法,只是统计,不真正查询数据!
集合属性默认有懒加载!

案例分析:
本本案列均来自Hibernate系列篇中讲解了部门与员工的案例,这里直接拿代码来测试了。如有不明白的地方,请参考作者之前的Hibernate笔记。

先测试get方法—Lazy使用默认值true.

@Test
    public void get_load() {

        Session session = sf.openSession();
        session.beginTransaction();
        Dept dept = new Dept();
        // get: 及时查询
        dept = (Dept) session.get(Dept.class, 9);
        System.out.println(“---------------------------”);
        System.out.println(dept.getDeptName());

        session.getTransaction().commit();
        session.close();        
    }

打印结果:先打印sql语句,再打印“————”,最后打印部门名称。说明get方法是直接执行数据库查询的(不犹豫,很果断)。

测试load方法

@Test
    public void get_load() {

        Session session = sf.openSession();
        session.beginTransaction();
        Dept dept = new Dept();
        // get: 及时查询
//      dept = (Dept) session.get(Dept.class, 9);
//      System.out.println(dept.getDeptName());

        // load,默认懒加载, 及在使用数据的时候,才向数据库发送查询的sql语句!
        dept = (Dept)session.load(Dept.class, 9);
 System.out.println(“---------------------------”);
// 在这里使用
        System.out.println(dept.getDeptName());


        session.getTransaction().commit();
        session.close();


    }

打印结果;先打印“—————–”,再打印sql查询语句,最后再打印部门的名称。说明load方法使用了懒加载机制,在用到dept数据的时候才向数据库发送查询的sql语句!

注意:在session关闭之后,不能使用懒加载数据,也就是load查询到的数据比如user对象,如果在session.close()之后,进行user.getName()将会报错。

比如:代码如下:

@Test
    public void get_load() {

        Session session = sf.openSession();
        session.beginTransaction();
        Dept dept = new Dept();
        // get: 及时查询
//      dept = (Dept) session.get(Dept.class, 9);
//      System.out.println(dept.getDeptName());

        // load,默认懒加载, 及在使用数据的时候,才向数据库发送查询的sql语句!
        dept = (Dept)session.load(Dept.class, 9);
 System.out.println(“---------------------------”);

        session.getTransaction().commit();
        session.close();

// 在这里使用
        System.out.println(dept.getDeptName());     
    }

会报错!错误信息:org.hibernate.LazyInitializationException: could not initialize proxy - no Session

还有,在使用load方法时将会返回查询结果的代理对象。
例如:user=(User)session.load(User.class,1); 此时的user类型为User对象的代理对象。我们可以通过debug断点调试的方法查看dept的类型发生了变化。

懒加载在集合中的应用:

    @Test
    public void set() {
        Session session = sf.openSession();
        session.beginTransaction();
        Dept dept = (Dept) session.get(Dept.class, 10);
        System.out.println(dept.getDeptName());
        System.out.println("------");
        System.out.println(dept.getEmps());  //  SQL

        session.getTransaction().commit();
        session.close();

    }

打印顺序:先查询部门的sql语句,然后打印部门的名称,再打印“———–”,然后查询员工的sql语句,最后打印该部门下的全部的员工。这就是懒加载在集合中的应用,即如果在具体的实际开发中,我们只想要部门的名称等信息,不会去关心该部门下的具体员工,那么将lazy=true,会提高Hibernate对数据库操作的效率。

但是有些时候,我们又想查询部门的时候,也同时查出来员工的信息,那么就必须把lazy改为flase.因为有时在实际的项目中查询跟数据库操作有关,一般会放在service层中,如果在页面加载之前调用一次service层中的方法,就想查询部门和员工的信息,并且在页面中显示,那么怎么办呢?这就考虑关闭懒加载了。之后的项目开发案例中会给出具体的应用。

那么还有一点,如何解决session关闭后不能使用懒加载数据的问题?
// 方式1: 在session关闭之前先使用一下数据
//dept.getDeptName();

// 方式2:session关闭之前强迫代理对象初始化
Hibernate.initialize(dept);

// 方式3:关闭懒加载
设置lazy=false;

// 方式4: 在使用数据之后,再关闭session!

测试代码如下:

@Test
    public void get_load() {

        Session session = sf.openSession();
        session.beginTransaction();
        Dept dept = new Dept();
        // get: 及时查询
//      dept = (Dept) session.get(Dept.class, 9);
//      System.out.println(dept.getDeptName());

        // load,默认懒加载, 及在使用数据的时候,才向数据库发送查询的sql语句!
        dept = (Dept)session.load(Dept.class, 9);
        // 方式1: 先使用一下数据
        //dept.getDeptName();
        // 方式2:强迫代理对象初始化
        Hibernate.initialize(dept);
        // 方式3:关闭懒加载

        session.getTransaction().commit();
        session.close();

        // 在这里使用
        System.out.println(dept.getDeptName());
    }

最后,说一下集合中lazy=extra 的用法。
如果调用集合的size()/isEmpty()方法,只是统计,不真正查询数据!

测试:

@Test
    public void set() {
        Session session = sf.openSession();
        session.beginTransaction();
        Dept dept = (Dept) session.get(Dept.class, 10);
        System.out.println(dept.getDeptName());
        System.out.println("------");
        System.out.println(dept.getEmps().isEmpty());  //  SQL

        session.getTransaction().commit();
        session.close();

    }

输出顺序:部门名称,“—-”然后是“select count(id) form t_employee‘’的sql语句,说明size或者isEmpty方法只会查询员工表的总记录数,不会查询员工的全部信息。这也算是一种优化策略!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值