Hibernate的查询优化、抓取策略

版权声明:电虫原创~转载时请注明出处! https://blog.csdn.net/qq_40762011/article/details/82993283

叙:在hibernate中存在类级别查询和关联级别查询两种,前一个是对一对多关系情况下使用的,后一个是对多对一关系情况下使用的,详细的请看下面的笔记;


Hibernate查询优化、抓取策略

延迟加载(lazy加载)先获取到的是索要查询的数据的代理对象,当真正使用到该对象中的数据的时候,才会发送SQL语句,这种机制是Hibernate框架提升性能的方式之一

类级别查询

类级别查询是指只查询一个类的数据,并不牵涉关联类的数据查询,类级别查询只有load()、get()两个查询方法,get()查询是即查即得类型的,load()查询是延迟加载(懒加载)类型的,运行到查询语句时并不会立即查询,而是运行到使用这个查询语句查询的结果才会执行查询语句,get()方法没有任何查询策略,load()方法需要策略进行配置,此配置只需要在此类的映射文件中的class标签中设置一个lazy属性,这个属性只有false、true(默认);
以下是get()、load()查询的使用;

@Test
	public void demo1(){
		Session session = HibernateUtils.openSession();
		Transaction bt = session.beginTransaction();
		
		//Customer cust = session.get(Customer.class, 2l);
		Customer cust = session.load(Customer.class, 2l);
		
		System.out.println(cust);
		
		bt.commit();
	}

两个方法,在使用方面并没有什么区别,而且如果直接运行demo的话并不会看的出来结果,要想看到结果需要在get()/load()行与打印输出那行各打一个断点,然后使用debug来进行查看;
会发现,代码运行到load()方法那一行时并不会有查询语句出现,当运行到打印那一行时也不会有任何反应,但是一旦数据有事务提交后就会使用关联的session进行数据库查询,加载数据,所查询的东西完全打印出来;但是如果是get()方法的demo的话,当运行到打印那一行的时候就会出现查询语句进行查询,当有事务提交时就会打印出来查询的结果;
在hibernate中有一个查询策略的,就是关于类级别的查询查略,同样在实体类的映射文件中进行配置,配置如下代码所示:

<hibernate-mapping package="com.java.domain" >
	<class name="Customer" table="cst_customer" lazy="true" >

在映射文件的中的class标签中,使用lazy属性,这个翻译过来就是懒,对应的是load()方法的别称–懒加载;其属性值只有false、true(默认值)这两个,true就是允许延迟加载(懒加载),false就是不使用懒加载,在使用false属性值配置的情况下使用load()方法是不会起到延迟加载的效果的,这时的load()方法和get()方法没有任何差别;

实验方法:
把lazy属性设置成false,然后debug运行一遍load()方法的demo,查看运行到打印、事务提交这两个点的代码输出情况,与不编写lazy属性时(其实lazy属性对get()方法没有任何影响,这样做是为了避嫌)get()方法的debug结果;

注意:
上面提到,load()方法懒加载是使用关联的session进行数据库查询并加载数据的,也就是说当关联的session关闭后查询到的代理对象也不存在了,查询也不存在了,代码如下所示:

@Test
	/*
	 * 错误代码演示:关联的session被销毁,查询终结
	 */
	public void demo2(){
		Session session = HibernateUtils.openSession();
		Transaction bt = session.beginTransaction();
		
		Customer cust = session.load(Customer.class, 2l);
		bt.commit();
		session.close();
		System.out.println(cust);
	}

session被销毁后这个session中所夹带的或者说所代表的数据已将被销毁,当再次调用这个session所关联的数据时会报如下图所示的错:
报错信息

结论:
为了提高效率,尽量使用load()方法;


关联级别查询

注意:关联级别查询在学习时比较拗脑^_^没错,就是拗脑,表述不清楚的地方还望海涵,多读几遍会清晰很多

关联级别查询是指,所要查询数据中包含这个类A的数据以及与这类A相关联类B的数据,即,查询的数据包含关联类数据;
关联级别查询分为集合查询和关联属性查询两种,集合查询就是以查询类为主,在查询类的文件中进行设置相应的配置,关联属性查询是指在关联类中设置相应的配置;
在类级别查询中我们了解了lazy属性,因为类级别查询不涉及到多个类的关联查询,因此不需要考虑集合查询的策略(抓取策略),而关联级别查询则需对查询的类加载问题进行配置;

集合查询策略
集合查询即是指一对多关系的情况下使用集合的查询策略,所使用的属性及其属性值、配置位置、代码展示以及总结:
属性名:属性值
Lazy属性:

属性值------------ 备注
true 延迟加载,懒加载(默认)
false 立即加载
extra 极其懒惰,查询的结果和懒加载效果类似,区别:如果只获得集合的size值,只需要查询集合的size(count语句),使用这个配置是比较方便的,但一般情况下最好还是不用此配置;

fetch属性:(抓取策略属性)

属性值------------ 备注
select 单表查询加载(默认)
join 使用多表查询加载集合
subselect 使用子查询加载集合:根据类A的多个Customer对象查询与之对应关联的所有LinkMan对象的信息;只有查询多个Customer对象的关联对象数据时才会使用subselect配置,当只查询一个Customer对象的关联对象数据时其效果和select的配置效果一样;

这些属性的配置位置:在类的映射文件中set标签中进行设置;
配置代码展示:

/*
*一般的抓取缓存策略demo:
*/
@Test
	public void demo1(){
		Session session = HibernateUtils.openSession();
		Transaction bt = session.beginTransaction();
		
		Customer cust = session.get(Customer.class, 2l);		
		System.out.println(cust);
		
		bt.commit();
	}

对应的映射文件配置:
映射文件配置

子查询(subselect查询集合方式)demo代码和一般的不太一样,因此拎出来单独记录;

/*
*子查询的Demo
*/
    @Test
    	/*
    	 * 关联查询:
    	 * fetch:subselect
    	 * lazy:true
    	 */
    	public void demo3(){
    		Session session = HibernateUtils.openSession();
    		Transaction bt = session.beginTransaction();
    		
    		String hql = "from Customer";
    		Query custs = session.createQuery(hql);
    		List<Customer> list = custs.list();
    		for (Customer customer : list) {
    			System.out.println(customer.getLinkMens());
    			System.out.println(customer.getLinkMens().size());
    		}
    		bt.commit();
    }

映射文件配置:
子查询文件配置

总结/注意:

  1. fetch的作用:控制抓取关联对象的时候发送的SQL语句的格式;
  2. lazy的作用:控制查询其关联对象的时候是否采用延迟加载;
  3. 当fetch设置成多表查询时(join),lazy不论设置什么值都是无效的;

关联属性查询策略

关联查询即是指多对一关系的类的映射文件进行配置,所使用的属性及其属性值、配置位置、代码展示以及总结:
Lazy属性:

属性值 备注
proxy 由关联他的类A的类级别加载策略决定;
false 立即加载

fetch属性:

属性值 备注
select 单表查询加载
join 使用多表查询加载集合

属性配置位置:在类的映射文件中的标签中进行设置
Demo:

@Test
	public void demo4(){
		Session session = HibernateUtils.openSession();
		Transaction bt = session.beginTransaction();
		
		LinkMan linkMan = session.get(LinkMan.class, 2l);
		Customer customer = linkMan.getCustomer();
		System.out.println(customer);
		
		bt.commit();
}

映射文件配置展示:
关联属性查询策略
注意:

  • 需要注意当使用懒加载的proxy属性值时,意为由关联这个B对象的A对象的类级别加载策略决定,注意,是A对象的类级别加载策略,就是写在class标签中进行配置的;

优化查询总结:

为了提高效率,fetch一般使用默认值select,lazy使用默认值true,即,全部使用默认值即可;


No-Session问题解决办法:

No-session 问题导致的原因是用到的数据对象所关联的session对象已经被清除,session对象所关联的数据需要在web、service、dao层中进行传递,最终查询的数据结果需要放到页面中展示给用户,因此要扩大session的作用范围,所使用的技术就是过滤器(filter),具体解决思路如下:
no-session问题解决办法思路图
既是,在经过过滤器时就会创建一个session,使用这个session直到放行完成所有操作后在进行清理session并提交事务;


pass:学完了查询优化和抓取策略基本上hibernate的入门什么的已经算是完成了,但是对于hibernate框架来说这只是皮毛,真正的学习是往后的研究探索,希望大家能有所建树对于此框架的学习~一起加油吧^_^
# 《本章完》

猜你喜欢

转载自blog.csdn.net/qq_40762011/article/details/82993283