懒加载之Load和get


       数据库中得到一个对象的两种方式,一种是session.get()方法;另一种就是通过session.load()方法。load支持懒加载机制(等到使用非主键时才去读库),而get方法不支持懒加载。


一、懒加载机制

       只有真正使用实体对象时,才发出Sql语句加载它。所谓真正使用实体对象时是指调用了对象的方法,其中不包括getId,getClass方法。

       情况1:当使用load方法加载实体时,会看映射文件中配置该类的class标签上的lazy属性,lazy=true才实现懒加载

       情况2:当使用load方法加载关联对象时,会看映射文件中配置该关联对象的标签上的lazy属性,然后再决定是否实现懒加载

     注:

           使用懒加载的前提是这个对象一定在数据库中存在,否则会抛出异常

           懒加载生命周期与session有关,lazy加载必须依赖于session一直开启,session关闭懒加载就失效,抛LazyInistialzationException


二、优点

        避免无谓的性能开销


三、懒加载配置

      <class>标签(lazy=true/false)

             只对普通属性的延迟加载有效,不包括集合和其他类属性

      <property>标签上,取值可以为true、false(需要增强类)

      <set><List>集合标签(true/false/extra)

             如果设置为true,那么就会在该集合被加载时发出SQL语句

             如果设置为false,那么在发出查询普通属性sql时就会随后发出集合的查询语句

             如果设置为extra,与设置为true类似,但相对智能,建议在实际工作中选用extra

       <one-to-one><many-to-one>单端关联标签(proxy/false/noproxy)

             如果取值为proxy,那么就会在类对象被加载时发出SQL语句

             如果设置为false,那么在发出查询普通属性sql时就会随后发出类对象的查询语句。


四、加载过程

1、load      

      User user=session.load(User.class,uid);

    (1)先查一下session缓存,看看该id对应的对象是否存在

    (2)缓存中没有这个对象,并且设置了延迟加载,就创建个代理;否则直接访问数据库,查到记录返回

        因为延迟加载需要代理来执行所以就创建了个代理,这个并没有去数据库交互查询。当你使用这个对象user.getName()或get()方法时候,此时才会触发sql语句。这时hibernate就去查询二级缓存和数据库,数据库没有这条数据就抛出异常ObjectNotFoundException

         如果只是获取他的id,则不会加载,不会出现select语句,只有获取他和本身之外才会进行查找,否则访问的只是它的代理对象而已。 因为load后会在hibernate的一级缓存里存放一个map对象,该map的key就是uid的值,但是当你getId()时,它会去一级缓存中那map的key值,而不去执行数据库查询。所以不会报任何错误,不会执行任何数据库操作。

2、get

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

    例如:User user=session.load(User.class,uid);

    (1) get方法首先查询session缓存

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

    (3) get方法如果在session缓存中找到了该id对应的对象,并且不是被延迟加载的代理对象,或者在session缓存中没有找到该对象,则查找二级缓存,再没有就查找数据库,返回的对象为实体对象,如果都没有找到,则返回null

                     

五、实例

      用户类和部门类是多对一的关系

      数据库:用户表(did是部门id)

     

1、load

        用户类不会立即载入,当我们取用户的姓名时,用户类载入了,但部门类仍然未载入。直到取部门的相关属性时,部门类才载入

(1)创建对象时不发出语句,真正使用对象时发出sql语句(用户ID为1时)

      

        注:load方法返回User的代理对象

       


(2)获取主键ID时不发出语句,只有获取非主键属性时才发出语句(用户ID为1时,查询用户信息,获取用户姓名)

     获取主键ID

  

    

     获取用户姓名(发送sql语句)

    

      原因:创建代理对象时,对象只保存实体的主键ID,所以在获取主键属性时,没有查询数据库,固不会有sql语句,即使查询的id在数据库中不存在,也不会报错

    

      不报错的原因是因为id保存在缓存中,查询其他属性会报错


(3)查询时对象不存在,报错ObjectNotFoundException

       用户id为3时,查询用户姓名:

 

 

2、get

     用户类会马上被载入,而部门类仍然是懒加载。只有用到部门类的时候,才会被载入部门实体。所以说用了get并不是说懒加载完全失效,直接操作的类会直接载入,引用类仍然按照配置懒加载。

(1)创建对象时就发出语句 (用户id为1,查询用户信息和部门信息)

	@Test
	public void testGet(){
		Session session=null;
		try {
			session=HibernateUtils.getSession();
			session.beginTransaction();
			long uid=1;
			
			System.out.println("——————————查询方式get————————————");
			System.out.println("查询前——创建对象");
			Object object=session.get(User.class,uid);
			
			System.out.println("查询后——查看对象");
			User user=(User) object;
			System.out.println(user);
			
			System.out.println("查询后——使用对象");
			System.out.println(user.getDepartment().getDid());
	
			session.getTransaction().commit();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

结果:



注:返回真实的User对象。get方法返回的是实体对象本身,而load方法返回是实体对象的cglib代理类

     

    (2)如果对象不存在,直接返回null( 查询用户id为3,获取用户信息和部门信息)

      


六、几种情况:

      情况1:当调用Session上的load()方法加载一个实体时,会采用延迟加载

      情况2:当Session加载某个实体时,会对这个实体中的集合属性值采用延迟加载

      情况3:当Session加载某个实体时,会对这个实体多单端关联(一对一,多对一)的另一个实体对象采用延迟加载


七、关闭延迟加载

     (1)加载实体普通属性的同时,加载实体中的集合属性。在集合标签上添加属性lazy="false"

     (2)加载某个实体时,不需要对这个实体单端关联的另一个实体对象延迟加载,在配置文件的配置元素(<one-to-one>,<many-to-one>添加属性lazy="false")


总结:

         hibernate3以后默认启用了延迟加载:lazy="true"。hibernate对于load方法,认为该数据在数据库中一定存在,可以放心的使用代理来延迟加载,如果在使用过程中发现问题,就抛异常;对于get方法,hibernate一定要获取真实的数据,否则返回null。get是比load安全的,但是安全性是要牺牲性能的。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值