Hibernate优化_Hibernate性能优化_Hibernate优化方案(上):[url]http://xiexiejiao.cn/hibernate/hibernate-performance-optimization-a.html[/url]
Hibernate优化_Hibernate性能优化_Hibernate优化方案(下):[url]http://xiexiejiao.cn/hibernate/hibernate-performance-optimization-b.html[/url]
Hibernate性能优化 [url]http://blog.itpub.net/9759696/viewspace-423064/[/url]
Hibernate性能优化2 [url]http://blog.itpub.net/9759696/viewspace-423065/[/url]
Hibernate性能优化4 [url]http://blog.itpub.net/9759696/viewspace-423066/[/url]
Hibernate 二级缓存 和 查询缓存 [url]http://benx.iteye.com/blog/990668[/url]
二级缓存和查询缓存都相当于一个map。
二级缓存缓存的key为id,value为实体对象。一般load,get ,iterate使用到二级缓存,list()需要结合查询缓存使用。
[color=blue][size=large]iterate和list区别如下:[/size][/color]
[color=red][size=large]iterate不需要开启查询缓存[/size][/color],它首先发出一个sql如”select s.id from Student s”去数据库把id属性列表取出来,然后再根据id列表一个一个load(),如果缓存有从缓存取,如果缓存没有就从数据库取:select s.id,s.name,s.classid from Student s where s.id=?,取出后再存入二级缓存。Iterate总会发出取id列表的语句。
[color=red][size=large]List需要开启查询缓存[/size][/color],它首先发出一个sql如”select s.id,s.name,s.classid from Student s…”去数据库取出所有相关实体,并将这些实体存入二级缓存,将此sql语句及一些相关信息作为key,id列表作为值,第二次查询这条语句时就会去根据sql语句及相关信息去key里找,如果有就会把id列表取出一个一个load(),接下来就和iterate一样了。List一般只有第一次发发出取实体列表的语句,以后的id列表就会去查询缓存取id列表,不会再发出sql语句。
[b]第一次查询: [/b]
iterator,查询所有id,然后缓存查询或者数据库查询并缓存单个实例;
list查询所有实体,然后缓存id列表。
[b]第二次:[/b]
iterator, 如同第一次一样,都要发送查询所有id的sql;
list, 从缓存中得到id列表,然后再从缓存或数据库查询。
[color=red][size=medium]对于一条记录,也就是一个PO来说,是根据ID来找的,缓存的key就是ID,value是POJO。无论list,load还是iterate,只要读出一个对象,都会填充缓存。但是list不会使用缓存,而iterate会先取数据库select id出来,然后一个id一个id的load,如果在缓存里面有,就从缓存取,没有的话就去数据库load。[/size][/color]
Query和list/iterator,如果去仔细研究一下它们,你可能会发现很多有意思的情况,二者主要区别(如果使用了Spring,在HibernateTemplate中对应find,iterator方法):
[b] i. list只能利用查询缓存[/b](但在交易系统中查询缓存作用不大),无法利用二级缓存中的单个实体,但list查出的对象会写入二级缓存,但它一般只生成较少的执行SQL语句,很多情况就是一条(无关联)。
[b] ii. iterator则可以利用二级缓存[/b],对于一条查询语句,它会先从数据库中找出所有符合条件的记录的ID,再通过ID去缓存找,对于缓存中没有的记录,再 构造语句从数据库中查出,因此很容易知道,如果缓存中没有任何符合条件的记录,使用iterator会产生N+1条SQL语句(N为符合条件的记录数)
[b] iii. 通过iterator,配合缓存管理API,在海量数据查询中可以很好的解决内存问题[/b],如:
while(it.hasNext()){
YouObject bject = (YouObject)it.next();
session.evict(youObject);
sessionFactory.evice(YouObject.class, youObject.getId());
}
如果用list方法,很可能就出OutofMemory错误了。
iv. 通过上面的说明,我想你应该知道如何去使用这两个方法了。
[color=red][b]Robbin总结的Hibernate性能优化要点[/b][/color]:
1.尽量使用many-to-one,避免使用单项one-to-many
2.灵活使用单向one-to-many
3.不用一对一,使用多对一代替一对一
4.配置对象缓存,不使用集合缓存
5.一对多使用Bag 多对一使用Set
6.继承使用显示多态 HQL:from object polymorphism="exlicit" 避免查处所有对象
7.消除大表,使用二级缓存
对于上面这些,Robbin进行了详细的讲解。
[b]one-to-many:[/b]
使用inverse=false(default),对象的关联关系是由parent对象来维护的
而inverse=true的情况下,一般用户双向多对多关联,由子对象维护关联关系,增加子对象的时候需要显示:child.setParent(child)
为了提高性能,应该尽量使用双向one-to-many inverse=true,在MVC结构中的DAO接口中应该直接用Session持久化对象,避免通过关联关系(这句话有点不理解),而在单项关系中正确使用二级缓存,则可以大幅提高以查询为主的应用。
多对一性能问题比较少,但是要避免经典N+1问题。
通过主键进行关联,相当于大表拆分小表。(这个是区分面向对象设计和面向过程设计的一个关键点)
[b]list、bag、set的正确运用[/b]
one-to-many:
A、使用list 需要维护Index Column字段,不能被用于双向关联,而且必须使用inverse=false,需要谨慎使用在某些稀有场合(基本上是不予考虑使用)
B、bag/set在one-to-many中语义基本相同,推荐使用bag
many-to-one:
A、bag和set不同,bag允许重复插入,建议使用set
[b]在庞大的集合分页中应该使用session.createFilter[/b]
session.createFilter(parent.getChildren(),""),setFirstResult(0),setMaxResult(10))
[b]避免N+1 参考[/b]([url]http://www.iteye.com/post/266972[/url])
在多对一的情况下,查询child对象,当在页面上显示每个子类的父类对象的时候会导致N+1次查询,需要采用下面的方法避免:many-to-one fetch="join|select"(该方法可能有问题)
[b]inverse=true 无法维护集合缓存(还不是很理解集合缓存和对象缓存)
OLTP类型的web应用,可以群集水平扩展,不可避免的出现数据库瓶颈[/b]
框架能降低访问数据库的压力,采用缓存是衡量一个框架是否优秀的重要标准,从缓存方面看Hibernate
A、对象缓存,细颗粒度,是针对表的级别,透明化访问,因为有不改变代码的好处,所以是ORM提高性能的法宝
B、Hibernate是目前ORM框架中缓存性能最好的框架
C、查询缓存
[b]最后Robbin还针对大家经常出现的Hibernate vs iBatis的讨论进行了一个总结:[/b]
对于OLTP应用,使用ORM框架 而OLEB应用(不确定是什么应用)最好采用JDBC或者其他方法处理
Hibernate倾向于细颗粒度设计,面向对象,将大表拆分为多个小表,消除冗余字段,通过二级缓存提升性能。
iBatis倾向于粗颗粒度设计,面向关系,尽量把表合并,通过Column冗余,消除关联关系,但是iBatis没有有效的缓存手段。
标签:缓存,url,list,查询,调优,Hibernate,优化,id From: https://blog.51cto.com/u_3871599/6410622