hibernate 延迟加载
Posted xiaohu666
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hibernate 延迟加载相关的知识,希望对你有一定的参考价值。
延迟加载
延迟加载:
当hibernate从数据库中加载某个对象时,不加载关联的对象,而只是生成了代理对象。使用session中的load的方法(在没有改变lazy属性,属性值为true的情况下)获取到的也是代理对象。
立即加载:
当Hibernate从数据库中加载某个对象时,加载关联的对象,生成实际的对象。使用session中的get的方法获取到的也是实际对象。
延迟加载的好处:
延迟加载策略能避免加载应用程序不需要访问的关联对象,以提高应用程序的性能。
立即加载的缺点:
Hibernate在查询某个对象时,立即查询与之关联的对象:
1、当select的语句数目太多,需要频繁的访问数据库,会影响查询的性能。
2、在应用程序只需要访问要的对象,而不需要访问与他关联的对象的场景下,加载与之关联的对象完全是多余的操作,这些多余的操作是会占内存,这就造成了内存空间的浪费。
延迟加载的原理图:
Hibernate的lazy生效期:
生效期和session一样的,session关闭,lazy失效。hibernate支持lazy策略只在session打开状态下有效。如果session已经关闭了,则会抛出LazyInitalizationException异常
Hibernate lazy属性,在3.x后是默认打开的,在以前版本中默认是关闭的
hibernate在对象关系映射文件中配置加载策略的方式:(lazy)
1、类级别
元素中lazy属性的可选值为true(延迟加载)和false(立即加载);
元素中的lazy属性的默认值为true
2、一对多关联级别:
元素中的lazy属性的可选值为:true(延迟加载),extra(增强延迟加载)和false(立即加载);
元素中的lazy属性的默认值为true
extra其实是一种比较智能的延迟加载,即调用集合的size/contains等方法的时候,hibernate并不会去加载整个集合的数据,而是发出一条聪明的SQL语句,以便获得需要的值,只有在真正需要用到这些集合元素对象数据的时候,才去发出查询语句加载所有对象的数据。
3、多对一关联级别:
元素中lazy属性的可选值为:proxy(延迟加载),no-proxy(无代理延迟加载)和false(立即加载)
元素中的lazy属性的默认值为proxy
load和hibernate的主要的区别:
1、load采用的是延迟加载,get 不能采用延迟加载技术而是立刻加载
2、load方法认为数据库中一定存在要检索的数据,可以放心的使用代理来延迟加载,如果在使用过程中发现了问题,那么只能抛出异常ObjectNotFoundException;而对于get方法,Hibernate一定要获取到真实的数据才会返回对象,否则返回null。
3、load方法可以返回一个没有加载实体数据的代理类实例,而get方法永远返回有实体数据的对象。
(对于load和get方法返回类型:好多书中都说:“get方法永远只返回实体类”,实际上并不正确,get方法如果在session缓存中找到了该id对应的对象,如果刚好该对象前面是被代理过的,如被load方法使用过,或者被其他关联对象延迟加载过,那么返回的还是原先的代理对象,而不是实体类对象,如果该代理对象还没有加载实体数据(就是id以外的其他属性数据),那么它会查询二级缓存或者数 据库来加载数据,但是返回的还是代理对象,只不过已经加载了实体数据。)
下面介绍get和post方法的具体用法及事例。
我的工具类:主要是用来创建session工厂并打开session的。下面两个事例中会用到这个类
public class SessionFactoryUtils private SessionFactory factory; private static SessionFactoryUtils factoryUtils; // 单例模式:把构造方法设置为私有的,说明不可以new这个类的实例。 private SessionFactoryUtils() // 通过定义这个类的静态方法,并且返回类型与这个类的类型一样,来实现对这个类的访问 public static SessionFactoryUtils getInstance() if (factoryUtils == null) factoryUtils = new SessionFactoryUtils(); return factoryUtils; public SessionFactory openSessionFactory() if (factory == null) //加载主配置文件 Configuration configuration = new Configuration().configure(); //建立工厂 factory = configuration.buildSessionFactory(); return factory;
get方法的加载方式
1、因为hibernate规定get方法不使用延迟加载,所以hibernate会去确认该id对应的数据是否存在
2、它会首先在session缓存中查找
3、如果session中找不到,就会去二级缓存中查找
4、如果二级缓存中还是没有找到,就会去数据库中查找
5、如果数据库中还是找不到就返回null。
代理对象实际就是空的对象,并没有去数据库中查询,所以我们叫做代理对象。如果取数据库查询了,返回了真实的对象,我们就叫做实体对象。
junit测试类:测试get方法
@org.junit.Test public void query() //调用我上面定义的工具类,通过调用定义的方法来创建session工厂并打开session private SessionFactory sessionFactory = SessionFactoryUtils.getInstance().openSessionFactory(); Session session = sessionFactory.openSession(); Admins adminsGet = session.get(Admins.class, 4); System.out.println(adminsGet);
控制台输出:可以发现在直接得到id的时候,它就发起了sql语句去数据库中查询了。并没有延迟加载。
Hibernate: select admins0_.aid as aid1_0_0_, admins0_.adminname as adminnam2_0_0_, admins0_.adminpwd as adminpwd3_0_0_ from admins admins0_ where admins0_.aid=? 4 ------- 4,nowyou
Load的加载方式
1、Load采用延迟加载的方式,hibernate的思想是既然这个方法支持延迟加载,它就认为这个对象一定在数据库中存在,可以放心的使用代理来延迟加载,如果在使用过程中出现了问题就放心的抛异常
2、Load方法会首先查询session缓存,看缓存中有没有这个对象
3、如果缓存中没有这个对象就会去创建个代理对象来管理,因为延迟加载需要代理来执行。但是并没有去数据库中查询
4、只有当你实际使用这个对象的时候,它才会触发sql语句。这个时候hibernate就会去查询二级缓存和数据库,如果数据库中没有这条语句,就抛出异常ObjectNotFoundException。
hibernate load方法加载实体对象的时候,会根据映射文件上 类级别 lazy属性值的配置,分情况讨论:
(1)若为true,即为延迟加载,就是上面的模式
(2)若为false,即为非延迟加载,即立即加载。就跟get方法查找顺序一样,只是最终若没发现符合条件的记录,则会抛出一个ObjectNotFoundException。
junit测试类:load方法:
@org.junit.Test public void query() //调用我上面定义的工具类,通过调用定义的方法来创建session工厂并打开session private SessionFactory sessionFactory = SessionFactoryUtils.getInstance().openSessionFactory(); Session session = sessionFactory.openSession(); Admins adminsLoad = session.load(Admins.class, 4); System.out.println(adminsLoad.getAid()); System.out.println("-------"); System.out.println(adminsLoad.getAid()+","+adminsLoad.getAdminname());
1、当类级别lazy属性值为false,即不适用延迟加载的时候:
<hibernate-mapping> <class name="org.danni.model.entity.Admins" table="admins" lazy="false"> <id name="aid" column="aid"> <generator class="native"></generator> </id> <property name="adminname" column="adminname"></property> <property name="adminpwd" column="adminpwd"></property> </class> </hibernate-mapping>
控制台输出:可以发现没有采用延迟加载,当直接输出id就调用了sql去查询,采用立即查询的方式
Hibernate: select admins0_.aid as aid1_0_0_, admins0_.adminname as adminnam2_0_0_, admins0_.adminpwd as adminpwd3_0_0_ from admins admins0_ where admins0_.aid=? 4 ------- 4,nowyou
2、当lazy属性为true的时候,即采用延迟加载:
<hibernate-mapping> <class name="org.danni.model.entity.Admins" table="admins" lazy="true"> <id name="aid" column="aid"> <generator class="native"></generator> </id> <property name="adminname" column="adminname"></property> <property name="adminpwd" column="adminpwd"></property> </class> </hibernate-mapping>
控制台输出:可以发现,当只是得到id的值的时候并没有取数据库中查询,而是创建了个代理对象来管理。这个代理对象中只保存了实体对象的id。但是当使用这个对象,获得这个对象的名字的时候他才触发了sql语句,它才去二级缓存、数据库中查找。
4
-------
Hibernate: select admins0_.aid as aid1_0_0_, admins0_.adminname as adminnam2_0_0_, admins0_.adminpwd as adminpwd3_0_0_ from admins admins0_ where admins0_.aid=?
4,nowyou
原文链接:https://blog.csdn.net/qq_36748278/article/details/78048406
以上是关于hibernate 延迟加载的主要内容,如果未能解决你的问题,请参考以下文章