• Hibernate中get()和load()的区别


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

    1. get()

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

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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=?

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

    image

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

    2. load()

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

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

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

    返回值:

    image 

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

    image 

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

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

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

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

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

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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

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

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

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

    image 

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

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

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

    抛出了ObjectNotFoundException异常:

    image

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

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

    再来看下面这段代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    @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()则返回代理对象。

    来看下面这段代码:

    1
    2
    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

  • 相关阅读:
    iOS的一些面试题分析总结(1)
    iOS的一些面试题分析总结(0)
    iOS页面间传值的一些方式总结
    自定义UIButton
    iOS查看3D效果的手势交互
    关于php得到参数数据
    ios安装ipa与安卓安装apk
    听说程序员想当就能当?
    W5100S、W5500、W5100差异对比
    annot read lifecycle mapping metadata for artifact org.apache.maven.plugins:maven-clean-plugin:maven
  • 原文地址:https://www.cnblogs.com/xiaohu666/p/11419357.html
Copyright © 2020-2023  润新知