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=?

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

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

2. load()

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

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

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

返回值:

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

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

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

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已经被填充上了:

3. Exception

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

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

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

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

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

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

抛出了ObjectNotFoundException异常:

这个就有点奇怪了,这个是因为我们使用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:

这个是因为我们使用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");

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

会发现两个都是真实对象,连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

【hibernate】Hibernate中get()和load()的区别的更多相关文章

  1. Hibernate中get()和load()方法区别

    get和load方式是根据id取得一个记录下边详细说一下get和load的不同,因为有些时候为了对比也会把find加进来. 1.从返回结果上对比:load方式检索不到的话会抛出org.hibernat ...

  2. Hibernate中get()和load()的区别

    Hibernate中根据Id单条查询获取对象的方式有两种,分别是get()和load(),来看一下这两种方式的区别. 1. get() 使用get()来根据ID进行单条查询: User user=se ...

  3. Hibernate中get()与load()的区别,以及关于ThreadLocal的使用方法

    一.get方法和load方法的简易理解 (1)get()方法直接返回实体类,如果查不到数据则返回null.load()会返回一个实体代理对象(当前这个对象可以自动转化为实体对象),但当代理对象被调用时 ...

  4. Hibernate中Session.get()/load()之区别

    原文链接http://sunxin1001.iteye.com/blog/292090 Session.load/get方法均可以根据指定的实体类和id从数据库读取记录,并返回与之对应的实体对象.其区 ...

  5. Hibernate 中 get()和load()的区别

    一.1.程序检索数据库中不存在的OID:     load方式检索不到的话会抛出org.hibernate.ObjectNotFoundException异常     get方法检索不到的话会返回nu ...

  6. Hibernate中get和load的区别

    get获取的对象立即执行sql查询数据库中当前实体表中的数据,如果外键关联的其他实体表如果配置了懒加载关闭,则也会查询出外键关联的其他实体表中的数据,否则外键关联的其他实体表则以代理对象表示(称其为代 ...

  7. hibernate延迟加载之get和load的区别

    在hibernate中我们知道如果要从数据库中得到一个对象,通常有两种方式,一种是通过session.get()方法,另一种就是通过session.load()方法,然后其实这两种方法在获得一个实体对 ...

  8. hibernate的get方法和load方法区别

    读者需注意:Hibernate版本不同,运行机制不太一样,以下是hibernate3.x作为讲解 get方法: Hibernate会确认一下该id对应的数据是否存在,首先在session缓存中查找,然 ...

  9. DOM加载过程中ready和load的区别

    在浏览器地址栏输入URL地址,浏览器开始加载页面时,有以下几个过程 1.浏览器开始解析HTML文档 2. 浏览器遇到HTML文档中的<script>元素以及CSS样式文件,并且没有asyn ...

随机推荐

  1. c++,友元类和友元函数

    都是声明时友元的东西可以访问自己类的私有和保护成员 类的友元 友元是C++提供的一种破坏数据封装和数据隐藏的机制. 通过将一个模块声明为另一个模块的友元,一个模块能够引用到另一个模块中本是被隐藏的信息 ...

  2. [转载]C语言头文件的作用

    最近在工作当中遇到了一点小问题,关于C语言头文件的应用问题,主要还是关于全局变量的定义和声明问题.学 习C语言已经有好几年了,工作使用也近半年了,但是对于这部分的东西的确还没有深入的思考过.概念上还是 ...

  3. An entity cannot be annotated with both @Entity and @MappedSuperclass: com.example1.demo1.Entity.User错误

    项目问SpringDataJpa项目,在运行的过程中出现的以下错误: Caused by: org.hibernate.AnnotationException: An entity cannot be ...

  4. ogre3D学习基础11 -- 日志文件的使用与异常处理

    用文件来记录 Ogre 系统初始化.运行.结束以及调试信息.使用日志便于我们调试程序.Ogre 日志系统由两个类组成:Log 类与 LogManager. 1.Log类 Log 类的一个对象对应于一个 ...

  5. 浅析win32 Win64 x86 x64 区别 及Eclipse启动报Java was started but returned exit code=13 错误

    win32.x86_64是64位 X86就是  32位系统 X64 就是64位系统 最好记得方法就是带有64的就是64位,其余都是32位 为什么要讲这个呢? 如果是绿色版本的eclipse,在打开ec ...

  6. selenium - 常用浏览器操作方法

    常用浏览器操作 (1)初始化浏览器会话: from selenium import webdriver driver = webdriver.Chrome() (2)浏览器最大化操作: driver. ...

  7. 【Luogu】P2351吊灯(脑洞后模拟)

    题目链接 这题要智商qwq.玩不来玩不来. 观察到(个P,能观察到的全都是dalao)x是解的充要条件是至少有n/x个节点的size是x的倍数. 证明请看这里 然后这题就变模拟了呀. #include ...

  8. 通过rabbitmqadmin管理rabbitmq

    # 安装rabbitmq $ sudo apt install rabbitmq-server # 下载rabbitmqadmin管理工具 sudo rabbitmq-plugins enable r ...

  9. 【BJOI2014/bzoj4530】大融合

    题意 有 $n$ 个点,初始没有连边,要求支持两个动态操作: 1. 加一条边(保证之前两点不连通) 2. 查询过一条边的简单路径数量(就是两边连通块的大小的乘积) $n,Q\le 100000$ 题解 ...

  10. bzoj 2795 [Poi2012]A Horrible Poem hash+线性筛

    题目大意 bzoj 2795 给出一个由小写英文字母组成的字符串S,再给出q个询问,要求回答S某个子串的最短循环节. 如果字符串B是字符串A的循环节,那么A可以由B重复若干次得到. n<=500 ...