zoukankan      html  css  js  c++  java
  • Hibernate中get()和load()的区别

    Hibernate中根据Id单条查询获取对象的方式有两种,分别是get()和load(),来看一下这两种方式的区别。

    1. get()

    使用get()来根据ID进行单条查询:

    User user=session.get(User.class, "1");

    当get()方法被调用的时候就会立即发出SQL语句:

    Hibernate:
        select
            user0_.ID as ID1_1_0_,
            user0_.CREATETIME as CREATETI2_1_0_,
            user0_.UPDATETIME as UPDATETI3_1_0_,
            user0_.USERNAME as USERNAME4_1_0_,
            user0_.PASSWD as PASSWD5_1_0_
        from
            USER user0_
        where
            user0_.ID=?

    并且返回的对象也是实际的对象:

    使用get()和普通的单条查询并没有多大的区别。

    2. load()

    当使用load()进行查询的时候情况就变得很不一样了:

    User user=session.load(User.class, "1");

    当调用load()方法的时候会返回一个目标对象的代理对象,在这个代理对象中只存储了目标对象的ID值,只有当调用除ID值以外的属性值的时候才会发出SQL查询的。

    返回值:

    image 

    在handler中有一个属性叫做target,保存着被代理的对象:

    image 

    现在这个位置还是空的呢。

    当我们尝试下面的代码时:

    User user=session.load(User.class, "1");
    System.out.println(user.getId());
     

    因为我们只访问了ID属性,这个在代理对象中是已经存在的了,所以并不需要再去数据库中查询,因此并不会发出SQL查询语句。

    当使用到除ID以外的属性的时候,会发出SQL查询语句,比如尝试执行下面的代码:

    User user=session.load(User.class, "1");
    System.out.println(user.getUsername());

    会发现控制台打印了SQL查询语句:

    Hibernate:
        select
            user0_.ID as ID1_1_0_,
            user0_.CREATETIME as CREATETI2_1_0_,
            user0_.UPDATETIME as UPDATETI3_1_0_,
            user0_.USERNAME as USERNAME4_1_0_,
            user0_.PASSWD as PASSWD5_1_0_
        from
            USER user0_
        where
            user0_.ID=?

    这个时候再看代理对象的话,会发现target已经被填充上了:

    image 

    3. Exception

    下面的代码会报一个空指针异常:

    User user=session.get(User.class, "foobar");
    System.out.println(user.getUsername());

    上面的这段代码抛出了空指针异常 NPE:

    这个是很容易理解的,因为没有查询到的就空指针了嘛。

    而下面的这段代码则会报一个ObjectNotFoundException异常:

    User user=session.load(User.class, "foobar");
    System.out.println(user.getUsername());

    抛出了ObjectNotFoundException异常:

    image

    这个就有点奇怪了,这个是因为我们使用load()的时候返回的是一个代理对象,因为这个时候还没有进行查询,所以我们并没有办法确定要查询的对象到底存在不存在,所以使用load()查询的返回值是永远不会为空的,但是呢,当我们试图访问被代理的真实对象的时候,因为这个对象并不存在,所以就抛出了一个ObjectNotFoundException。

    还有一种说法是get()是用于不确定对象是否真的存在的情况,所以在查询出来后可以先进行一个空指针判断,而load()方法用于对象一定存在的情况下,不然等会儿使用的时候就可能会抛出ObjectNotFoundException了。

    再来看下面这段代码:

    @Test
    public void test_001(){
         
        SessionFactory sessionFactory=new Configuration().configure().buildSessionFactory();
        Session session=sessionFactory.openSession();
         
        User user=null;
         
        try {
            session.beginTransaction();
             
            user=session.load(User.class, "foobar");
             
            session.getTransaction().commit();
        } catch (Exception e) {
            session.getTransaction().rollback();
            e.printStackTrace();
        }finally{
            try {
                session.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
         
        System.out.println(user.getUsername());
         
    }

    抛出了一个LazyInitializationException:

    image

    这个是因为我们使用load()查询出来的对象只有在调用完非ID属性的时候才会去查询数据填充进来,但是查询数据的时候是需要依赖产生这个代理对象的那个Session去查询的,当我们将Session关闭后,再试图去访问非ID属性,它正打算拿着自己依赖的Session去数据库查询,一看Session竟然被关闭了,得,干脆抛出一个LazyInitializationException好了。

    解决办法就是在查询的时候思考一下,这个对象时候需要在Session关闭之后还能使用得到呢?如果是的话,那么我们使用get()来查询,或者手动调用空访问一个非ID属性让它把数据回填上先。

    4. 缓存

    get()和load()都会使用缓存,都是首先从一级缓存Session中查找,当找不到的时候再去二级缓存中查找,当查询不到的时候get()返回的是null,而load()则返回代理对象。

    来看下面这段代码:

    User user1=session.get(User.class, "1");
    User user2=session.load(User.class, "1");

    来看一下这两条执行过后这两个变量的值:

    image

    会发现两个都是真实对象,连load()返回的也是真实对象,并且它们引用的还是同一块对象。

    这个是因为get()查询出来ID为1的对象后会将其放入到缓存中,而load()再去查询的时候它会先去缓存中查找,如果缓存中没有的话才会返回代理对象,但是当缓存中已经存在的话就直接将真实对象返回来了。

    5. 对比总结

    返回值:

    get()返回的是查询出来的实体对象,而load()查询出来的是一个目标实体的代理对象。

    查询时机:

    get()在调用的时候就立即发出SQL语句查询,而load()在访问非ID属性的时候才会发出查询语句并且将被代理对象target填充上,但是如果这个动作发生在Session被关闭后的话就会抛出LazyInitializationException。

    查询结果为空时:

    get()抛出NullPointerException

    load()抛出ObjectNotFoundException

    文章转载自:https://www.cnblogs.com/cc11001100/p/6883790.html

  • 相关阅读:
    Microsoft Enterprise Library 5.0 系列(二) Cryptography Application Block (初级)
    Microsoft Enterprise Library 5.0 系列(五) Data Access Application Block
    Microsoft Enterprise Library 5.0 系列(八) Unity Dependency Injection and Interception
    Microsoft Enterprise Library 5.0 系列(九) Policy Injection Application Block
    Microsoft Enterprise Library 5.0 系列(三) Validation Application Block (高级)
    软件研发打油诗祝大家节日快乐
    从挖井的故事中想到开发管理中最容易忽视的几个简单道理
    ITIL管理思想的执行工具发布
    管理类软件设计“渔”之演化
    20070926日下午工作流与ITILQQ群 事件管理 讨论聊天记录
  • 原文地址:https://www.cnblogs.com/yichenscc/p/11244227.html
Copyright © 2011-2022 走看看