疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Hibernate中load和get的区别


 

      Hibernate中Session.load/get方法均可以根据指定的实体类和id从数据库读取记录,并返回与之对应的实体对象。其区别在于:

  1.get()方法直接返回实体类,load()方法可以返回实体的代理类实例。

  2.hibernate load是采用延迟机制(当lazy属性为true时) 而get不采用延迟机制(get语句马上读库)

  3.找不到符合条件的数据 get方法将返回null

  load将会报出ObjectNotFoundExcepion

  4.get支持多态查询,load只有在lazy=false的情况下才支持多态查询

  所谓多态查询,就是可以明确区分加载的是什么类型的对象,load采用代理机制无法支持

  延迟加载:Hibernate尽量延迟向数据库发送sql,它自己有一个缓冲区,先把sql放在里面,最后一起发送,减少网络开销和数据库开销。

  load方法原理:

  当对象.hbm.xml配置文件元素的lazy属性设置为true时,调用load()方法时则返回持久对象的代理类实例,此时的代理类实例是由运行时动态生成的类,该代理类实例包括原目标对象的所有属性和方法,该代理类实例的属性除了ID不为null外,所在属性为null值,查看日志并没有Hibernate SQL输出,说明没有执行查询操作,当代理类实例通过getXXX()方法获取属性值时,Hiberante才真正执行数据库查询操作。

  注意:

  01.StudentEh s=(StudentEh)session.load(StudentEh.class,10);

  02.

  03.System.out.println(s.getId());

  这两条语句同样不会产生sql语句,因为session.load后会在hibernate的一级缓存里存放一个map对象,该map的key就是id的值,但是当你getId()时,它是从一级缓存里取map的key值,而不去执行数据库查询。

  当对象.hbm.xml配置文件元素的lazy属性设置为false时,调用load()方法则是立即执行数据库并直接返回实体类,并不返回代理类。而调用get()方法时不管lazy为何值,都直接返回实体类。

  get方法原理:

  get方法,hibernate会确认一下该id对应的数据是否存在,首先在session缓存中查找,然后在二级缓存中查找,还没有就查数据库,数据库中没有就返回null。

  get方法如果在session缓存中找到了该id对应的对象,如果刚好该对象前面是被代理过的,如被load方法使用过,或者被其他关联对象延迟加载过,那么返回的还是原先的代理对象,而不是实体类对象,如果该代理对象还没有加载实体数据(就是id以外的其他属性数据),那么它会查询二级缓存或者数据库来加载数据,但是返回的还是代理对象,只不过已经加载了实体数据。

  总结描述:

  如果使用load方法,hibernate认为该id对应的对象(数据库记录)在数据库中是一定存在的,所以它可以放心的使用代理来延迟加载该对象。在用到对象中的其他属性数据时才查询数据库,但是万一数据库中不存在该记录,那没办法,只能抛异常,所说的load方法抛异常是指在使用该对象的数据时,数据库中不存在该数据时抛异常,而不是在创建这个对象时。由于session中的缓存对于hibernate来说是个相当廉价的资源,所以在load时会先查一下session缓存看看该id对应的对象是否存在,不存在则创建代理。所以如果你知道该id在数据库中一定有对应记录存在就可以使用load方法来实现延迟加载。

  而对于get方法,hibernate一定要获取到真实的数据,否则返回null。

  自己在开发过程中遇到的问题:

  我们用MyEclipse hibernate工具通过数据库生成的DAO类,它的findById方法是用的session.get()方法,这是即时获得pojo对象,如果是load方法,在执行完load后如果关闭了session,那在接下来用到这个pojo对象时就会报session已关闭的错误。