Hibernate3学习笔记(12)——Hibernate的性能优化

来源:互联网 发布:狙击枪设计图纸与数据 编辑:程序博客网 时间:2024/06/04 23:30

hibernate是对JDBC的轻量级封装,因此在很多情况下hibernate的性能比直接使用JDBC存取数据库要低。然而,通过正确的方法和策略,在使用hibernate的时候还是可以非常接近直接使用JDBC时的效率的,并且,在有些情况下还有可能高于使用JDBC的执行效率。

在进行hibernate性能优化时,需要从以下几个方面进行考虑:

  • 数据库设计调整
  • HQL优化
  • API的正常使用(如根据不同的业务类型选用不同的集合及查询API)
  • 主配置参数(日志、查询缓存、fetch_size、batch_size等)
  • 映射文件优化(ID生成策略、二级缓存、延迟加载、关联优化)。
  • 一级缓存的管理。
  • 针对二级缓存,还有许多特有的策略。
  • 事务控制策略。

1、设计阶段考虑的问题
一个好的数据库结构有利于系统性能的提升。这里所说的良好结构的数据库并不单纯是指满足数据库设计范式的数据库结构。这是因为,按照数据库范式所设计的数据库只能说在结构上是最优的,没有冗余数据等问题,但在生产过程中并不一定能获得最佳的性能。有时候适当地增加一些数据的冗余虽然增加了数据维护的难度,但可以极大地简化业务的查询,提高数据检索的效率。
数据库设计阶段考虑三个问题:

  • java建模
    在建立java对象模型的时候,要考虑数据库持久化的方便性,所建立的java对象模型应该很容易地被数据所存储,并且数据库中的表的结构也是越简单越好。

  • 数据库结构
    在设计数据库结构的时候也要考虑到是否可以容易地用java对象去表示。这里并不是简单的一个表对应一个对象的直接转换,更重要的是转换后的java对象应该能够描述出数据间的关系。

  • 业务需求

2、批量插入、更新、删除
在进行大批量数据操作的时候,如果处理不当,很可能会出现执行效率低下的情况。下面首先来介绍一下批量插入数据时应该注意的问题。

2.1、批量插入数据
插入大量数据时,如果一味调用session.save( )向数据库保存对象,那么就很可能出现out of memory异常。产生原因:由于hibernate的以及缓存是由hibernate自己进行管理的,并且只会存在于内存中,所以,在调用save()方法的时候会将所保存的对象都缓存起来,这样当数量巨大的时候就会出现内存溢出的情况下。
为了避免这种情况。需在调用save方法时,阶段性地刷新和清空一级缓存。
虽然通过设置可以使二级缓存不会发生溢出,但在进行大批量的插入操作时,最好还是要禁用二级缓存,毕竟将对象保存到二级缓存是要耗费一定时间的。在禁用二级缓存后可以避免录入大量数据所带来的性能问题。

2.2、批量修改和删除
在hibernate中,引入批量更新或删除数据的Hql语句。
如果要删除所有User对象; 使用HQL语句:

delete User

具体实例如下:

String hql = "delete User";Query query = seesion.createQuery( hql);int size = query.executeUpdate();

采用这种方式进行数据的修改和删除时与直接使用JDBC的方式在性能上相差无几,是推荐的方式。

2.3、使用SQL执行批量操作
在进行批量插入、修改和删除操作时,直接使用JDBC来执行原生态的SQL语句无疑会获得最佳的性能,这是因为在处理的过程中省略或者简化了一下处理内容:

  • HQL语句到SQL语句的转换;
  • java对象的初始化;
  • java对象的缓存处理;

但是在直接使用JDBC执行SQL语句时,有一个最重要的问题就是要处理缓存中的JAVA对象。

2.4、提升数据库查询的性能

  • sql语句的优化
  • 使用正确查询方法——get与load(有二级缓存使用load)
  • list()与iterator()的区别。
    (1)执行的查询不同
    list在执行时,是直接运行查询结果所需要的查询语句,而iterator方法则是先执行得到对象ID的查询,然后根据每个ID值去取得所要查询的对象。因此,对于list的查询只会执行一个SQL语句,而对于iterator方法的查询则可能需要执行N+1条SQL语句。
    (2)缓存的使用
    list()方法只能使用二级缓存中的查询缓存,而无法使用二级缓存对单个对象的缓存(但是会把查询出的对象放入二级缓存中)。所以,除非重复执行相同的查询操作,否则无法利用缓存的机制来提高查询的效率。
    iterator()方法则可以充分利用二级缓存。所以,缓存中对象的存在与否会影响到SQL语句的执行数量。
    (3)对于结果集的处理方法不同
    list方法会一次获得所有的结果集对象,而且它会依据查询的结果初始化所以的结果集对象。这在结果集非常大的时候必然会占据非常多的内存。甚至会造成内存溢出情况的发生。
    iterator方法在执行时不会一次初始化所有对象,而是根据对结果集的访问情况来初始化对象。因此在访问中可以控制缓存中对象的数量,以避免占用过多的缓存,导致内存溢出情况的发生。另一个好处是:如果只需要结果集中的部分记录,那么没有被用到的结果对象根本不会被初始化。所以,对结果集的访问情况也是调用iterator()方法时执行数据库SQL语句多少的一个因素。

2.5、使用正确的抓取策略

0 0