Hibernate的性能分析--懒加载、抓取策略、缓存策略


Hibernate的性能分析:
 
	影响性能的3个方面:懒加载、抓取策略、缓存策略
 
	说明:发出的sql语句越少,性能就越高。懒加载是研究什么时候发出SQL语句,抓取策略是研究怎么样发出SQL语句。
	  
懒加载:
	说明:主要研究类、集合、many-to-one在什么时候发出SQL语句并加载数据
	1,类的懒加载
		1,利用session.load方法可以产生代理对象
		2,在session.load方法执行的时候并不发出sql语句
		3,在得到其一般属性的时候发出sql语句
		4,只针对一般属性有效,针对标示符属性(id)是无效的
		5,默认情况就是懒加载
		6,session.load方法返回的是一个代理对象,要求类不能是final的,否则不能生成子类代理,就不能使用懒加载功能了。
		7,数组不能生产代理对象,故数组不能使用懒加载
	2,集合的懒加载(lazy)
		false  		当session.get时,集合就被加载出来了
		true(默认)  在get到集合的时候没有加载,只有在遍历集合的时候才加载
		extra		当对集合做count,min,max,sum等操作时,直接加载出操作结果,做其他操作时与值为true时相同。
	3,单端关联的懒加载(多对一)
		<many-to-one lazy="false/no-proxy/proxy">  no-porxy相当于true(默认)
		根据多的一端加载一的一端,就一个数据,几乎不影响性能,一般默认即可。
	注:当fetch="join" lazy="true" 时,如果不存在子查询,则此时lazy的值不起作用,即在session.get(Classes.class, 1L)时,student也查询出来了。
	
抓取策略:
	
	概念:由一个对象怎么样查询关联对象,怎么样对关联的对象发出SQL语句。
	1,主要研究对set集合的提取
	2,在Classes.hbm.xml文件中:classes和student的一对多关系:<set fetch="join/select/subselect">
		join(左外连接):如果把需求分析翻译sql语句,存在子查询,这个时候用该策略不起作用。	对于n+1问题:发出1条SQL语句
		select(默认):先查询一的一端,再查询多的一端。										对于n+1问题:发出 n+1 条SQL语句
		subselect(子查询):如果需求分析翻译成sql语句存在子查询,这个时候用该策略效率最高。	对于n+1问题:发出2条SQL语句
	注:当fetch="join" lazy="true" 时,如果不存在子查询,则此时lazy的值不起作用,即在session.get(Classes.class, 1L)时,student也查询出来了。
 
缓存策略:
 
	查询顺序:一级缓存、二级缓存、数据库
 
	一级缓存(session缓存):放私有数据
		1,存放在session中,生命周期就是session的生命周期
		2,一级缓存存放的数据都是私有数据:把session存放在threadlocal中,不同的线程是不能访问的,保证了数据的安全性
		3,把数据存放到一级缓存中的方式:利用session.save/update/load/get方法都可以存放在一级缓存中
		4,利用session.get/load方法可以得到一级缓存中的数据
		5,利用session.evict方法可以把一个对象从一级缓存中清空
		6,利用session.clear方法可以把session中的所有的数据清空
		7,利用session.Refresh方法把数据库中的数据同步到缓存中
		8,session.flush
			在session的缓存内部,会去检查所有的持久化对象
			   1,如果一个持久化对象没有ID值,则会发出insert语句
			   2,如果一个持久化对象有ID值,则会去对比,如果一样,则什么都不做,如果不一样,则发出update语句
			   3,检查所有的持久化对象是否有关联对象:检查关联对象的级联操作、检查关联对象的关系操作
			注:session.flush只是发出SQL语句了,并没有清空Session缓存!
		9,操作大量数据时,要防止Session中对象过多而导致内存溢出
			session.flush(); // 先刷出
			session.clear(); // 再清空
		
	二级缓存(sessionFactory缓存):放公有数据
		1,适用场合:
			1)数据不能频繁更新
			2)数据能公开,私密性不是很强
		2,存放在sessionFactory中,生命周期就是sessionFactory的生命周期
		3,hibernate本身并没有提供二级缓存的解决方案,二级缓存的实现是依赖于第三方供应商完成的
			ehcache、oscache、jbosscache、swamchache
		4,把数据存放到二级缓存中的方式:session.get方法和session.load方法都可以把数据同时存放在一级缓存和二级缓存中
		5,使用二级缓存的步骤
			1)在hibernate.cfg.xml中:
				<!-- 开启二级缓存 -->
				<property name="cache.use_second_level_cache">true</property>
				<!-- 二级缓存的提供商 -->
				<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
			2)让某一个对象拥有进入到二级缓存中的权限
				方案一:在hibernate.cfg.xml中
					<class-cache usage="read-only" class="com.jxn.hiberate.domain.Classes"/>
				方案二:在映射文件中
					<cache usage="read-only"/>
			3)使用
				session.get/session.load
		6,查询缓存:
			1,二级缓存是查询缓存的基础
			2,使用查询缓存的步骤
				1)在配置好二级缓存的基础上,在hibernate.cfg.xml文件中添加以下配置:
					<property name="cache.use_query_cache">true</property>
				2)使用
					Query query = session.createQuery("from Classes");
					
					// 允许该query访问查询缓存,classes里所有的数据要往查询缓存中存放了
					query.setCacheable(true);
					
					List<Classer> classerList = query.list();
					
					Query query2 = session.createQuery("from Classes");
					
					//允许该query2访问查询缓存
					query2.setCacheable(true);
					
					classerList = query.list();	
			3,注意:
				只有两次的SQL语句一样时(例如都是"from Classes"),查询缓存才能使用!

以上转自https://blog.csdn.net/wodewutai17quiet/article/details/48681179

 

类别级的赖加载:在持久化类的配置文件中,类标签<class>的lazy属性配置

/**

 *  session.get(): 立即加载.执行方法时立即发送sql语句查询结果

 *  session.load():赖加载,到使用该方法返回的对象时, 才会执行sql查询

 *  session.load()赖加载是否生效,可以在配置文件的Customer的类标签后面 加属性:

 *  lazy="false" 关闭赖加载,该属性默认为true。

 *  使用懒加载session.load()实际返回的是代理对象,代理对象中新加了handler属性

 */

public void fun1(){

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();

Customer c = session.load(Customer.class, 5l);

System.out.println(c);//赖加载在这里使用的时候才会 实际执行sql语句

tx.commit();

session.close();

}

 

关联别级的懒加载和抓取策略:

关联别级的懒加载策略:在持久化类的映射文件配置<set>标签和<many-to-one>标签的lazy属性.

抓取策略是指:通过一个持久化对象,去获取另一个他关联的持久化对象(自己的成员变量)的查询方式(普通查询,迫切左外链接,子查询).在映射文件中通过<set>和<many-to-one>标签的fetch属性来配置.

代码:

public void fun(){

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();

Customer c = session.get(Customer.class, 2l);

Set<LinkMan> linkMens = c.getLinkMens();//关联级别

System.out.println(linkMens.size());//测试及其赖加载

System.out.println(linkMens);//测试赖加载

tx.commit();

session.close();

}

<set>:标签lazy属性有三种取值

true:默认,赖加载

false:不采用赖加载

extra:及其赖加载,与懒加载效果基本一致.当只获得集合的size.只发出count查询语句

 

<set>:标签fetch属性有三种取值:

select:默认值,发送普通的select查询语句

join:发送迫切左外链接查询语句,如配置该值,set标签的lazy失效,会立即查询

subselect:发送子查询,查询关联语句

 

<many-to-one>:标签lazy属性有三种取值:

proxy:默认,取决于一的一方上的lazy属性值

false:不采用懒加载

no-proxy:

<many-to-one>:标签fetch属性有2种取值:

select:普通查询

join:迫切左外链接查询 lazy: 失效  

 

批量抓取:

1.配置:batch-size属性

<set name="linkMens" batch-size="2">

<key column="lkm_cust_id" ></key>

<one-to-many class="LinkMan"/>

</set>

2.测试代码

public void fun1(){

Session session = HibernateUtils.openSession();

Transaction tx = session.beginTransaction();

String hql = "from Customer ";

Query query = session.createQuery(hql);

List<Customer> list = query.list();

System.out.println("List<Customer>大小是:"+list.size());

for(Customer c:list){

//默认情况,Customer每获取一次联系人会查询一次该Customer的所有联系人(c.getLinkMens()).

//<set>下配置 batch-size="2" ,会一次性查询2个Customer的所有联系人,大大减少sql查询次数

System.out.println("该Customer联系人有:"+c.getLinkMens().size()+"个 :"+c.getLinkMens());

}

tx.commit();

session.close();

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值