Hibernate优化策略

https://blog.csdn.net/blueheart20/article/details/21019043

https://blog.csdn.net/yerenyuan_pku/article/details/70768603

引言:  Hibernate是目前Java领域事实上的ORM实现标准,它以优雅的方式解决了面向对象和面向Table之间的不匹配状态,是解决Java应用中数据持久化的框架。由于Hibernate自行管理从数据库中读入的数据,则容易出现内存占用过大的问题,那如何来解决这个问题或者降低这种问题出现的概率呢?本文将尝试把其中的若干策略进行总结。

1. 尽可能不用或者少用多对多,将其拆分为,一对多和多对一。

2.  根据程序中实际的需求,选择性加载表中的数据,除非必须,一般无需加载全部字段。

3.  在Hibernate中进行查询之时,使用分页降低,一次性的内存负载。

4.  在性能关键的地方,可以尝试使用经过优化的原生SQL,而非HQL

5.  主配置参数(日志,查询缓存,fetch_depth/fetch_size, batch_size等), 优化fetch_size/batch_size大小

大量写入日志,会产生巨大的IO操作,所以可以提高日志级别降低日志的写入量,亦或通过缓存批量的写入。

6.  延迟加载策略的使用,二级缓存的优化,关联表的优化。

7.  事务是数据库操作中非常影响性能的机制,在Hibernate操作中,只保留必须的Update/Delete/Insert的强制事务一致性

另外,排它锁/悲观锁,事务效率低但安全。基于Version字段的乐观锁,则反之。针对不同的数据库应用需要进行平衡,选取适当的平衡点。

8.  完成同样一件事,HIBERNATE提供了可供选择的一些方式,但具体使用什么方式,可能用性能/代码都会有影响。显示,一次返回十万条记录 (List/Set/Bag/Map等)进行处理,很可能导致内存不够的问题,而如果用基于游标(ScrollableResults)或 Iterator的结果集,则不存在这样的问题。

9.   Hibernate vs MyBatis

Hibernate倾向于细颗粒度设计,面向对象,将大表拆分为多个小表,消除冗余字段,通过二级缓存提升性能。
  iBatis倾向于粗颗粒度设计,面向关系,尽量把表合并,通过Column冗余,消除关联关系,但是iBatis没有有效的缓存手段。

10. 选择确当的查询方法

Hibernatne 查询分为两类:一类是得到单个对象,get()和load方法;另一类是得到结果集,list()和iterator()方法。

get()方法和load()方法的区别在于对二级缓存的使用上。load()方法会使用二级缓存,而get()方法在一级缓存没有找到的情况下会直接查询数据库,不会去二级缓存中查找。在使用中,对使用了二级缓存的对象进行查询时最好使用load()方法,以充分利用二级缓存来提高检索的效率。

list()方法和iterator()方法之间的区别可以从以下几个方面来进行比较。

a、  执行的查询不同

list()方法在执行时,是直接运行查询结果所需要的查询语句,而iterator()方法则是先执行得到对象ID的查询,然后再根据每个ID值去取得所要查询的对象。因此,对于list()方式的查询通常只会执行一个SQL语句,而对于iterator()方法的查询则可能需要执行N+1条SQL语句(N为结果集中的记录数)。

iterator()方法只是可能执行N+1条数据,具体执行SQL语句的数量取决于缓存的情况以及对结果集的访问情况。

b、  缓存的使用

list()方法只能使用二级缓存中的查询缓存,而无法使用二级缓存对单个对象的缓存(但是会把查询出的对象放入二级缓存中)。所以,除非重复执行相同的查询操作,否则无法利用缓存的机制来提高查询的效率。

iterator()方法则可以充分利用二级缓存,在根据ID检索对象的时候会首先到缓存中查找,只有在找不到的情况下才会执行相应的查询语句。所以,缓存中对象的存在与否会影响到SQL语句的执行数量。

c、  对于结果集的处理方法不同

list()方法会一次获得所有的结果集对象,而且它会依据查询的结果初始化所有的结果集对象。这在结果集非常大的时候必然会占据非常多的内存,甚至会造成内存溢出情况的发生。

iterator()方法在执行时不会一次初始化所有的对象,而是根据对结果集的访问情况来初始化对象。因此在访问中可以控制缓存中对象的数量,以避免占用过多缓存,导致内存溢出情况的发生。使用iterator()方法的另外一个好处是,如果只需要结果集中的部分记录,那么没有被用到的结果对象根本不会被初始化。所以,对结果集的访问情况也是调用iterator()方法时执行数据库SQL语句多少的一个因素。

所以,在使用Query对象执行数据查询时应该从以上几个方面去考虑使用何种方法来执行数据库的查询操作。

数据库优化:

1.  降低Table之间关联的复杂度,适当进行数据的冗余,提高性能。

2.  减少多级关联的使用

3. 推荐使用lazy加载

这里只是单纯地从hibernate本身出发来介绍如何优化应用,其实从实际优化和性能提升的角度,我们关注的范围远不止此,更多地还是要从系统的维度和业务维度来进行系统优化和提升。

上一篇:python学习日记(内置函数)


下一篇:基于MVC4+EasyUI的Web开发框架经验总结(5)--使用HTML编辑控件CKEditor和CKFinder