Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行非常轻量级的封装,使得JAVA
程序员可以随心所欲地使用对象编程思维来操作数据库。
Hibernate性能优化
第一,尽量降低访问数据库的次数
Cache:hibernate中有两次缓存,一级位于Session部分是必需的,第二级位于
SessionFactory的外置缓存(SessionFactory缓存分两类,内置缓存和外置缓存,其中内置缓存
存放映射元数据和预定义SQL语句,映射元数据是映射文件中数据的拷贝,而预定义SQL语句是在
hibernate初始化阶段根据映射元数据推导出来的),二级缓存不是必需的,由开发人员自行指定
,二级缓存能明显提高系统性能,但同时也会消耗内存,可通过配置文件来指定内存中能够加载
的最多元素,有利于避免消耗过多内存。
在批量更新和批量删除时,通过绕过hibernate API,直接通过JDBC API来执行SQL语句,可
以提高效率。
比如更新一万条记录
tx = session.beginTransaction();
Connection con = session.connection();
PreparedStatement stmt = con.prepareStatement("update Customer set age=age+1
where age>0");
tx.commit();
当然,使用存储过程效果更佳
create or replace procedure batchUpdateCustomer(p_age in number) as
begin
update customer set age=age+1 where age>p_age;
end;
tx = session.beginTransaction();
Connection con = session.connection();
String procedure = "{call batchUpdateCustomer(?)}";
CallableStatement cstmt = con.prepareCall(procedure);
cstmt.setInt(1,0);
cstmt.executeUpdate();
tx.commit();
二级缓存的设置,第一种直接在hbm.xml中增加Cache元素,指明使用策略,如read-
only,read-write等。
<class name="" table="">
<cache usage="read-write"/>
...........
配置echcache.xml
<ehcache>
<diskStore path="c:\\temp"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<cache name="mypack.class"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
</ehcache>
第二适当的检索方式
延迟检索:对一些基本属性字段将其lazy设置为false,而对于一些可能需要消耗内存的字段
,如clob,将其lazy设置为true,对于集合全部设为true。(class和set中有些属性)
不管是延迟检索还是立即检索都可以通过batch-size设置批量检索的数量。合理取值在3-10
间(class和set元素中有些属性)。
第三避免无用的查询
使用投影查询,只查出实例的一部分字段
使用iterate()方法,在有些情况下轻微提高查询性能。因为iterate()首先检索ID字段,然
后根据ID字段到hibernate的第一级缓存及二级缓存中查找匹配的对象,若存在,直接加入到检
索结果集中,否则执行额外的select语句,根据ID字段到数据库中检索对象。
使用查询缓存,这样第一次执行查询语句时,会把查询结果放在第二级缓存中,注意二级缓
存中存放的只是实体的OID,对投影查询,会存放所有的数据值。
启用查询缓存步骤:
1.配置二级缓存
2.在hibernate的hibernate.properties配置文件中设置查询缓存属性;
hibernate.cache.use_query_cache=true
3.Query query = session.createQuery("from customer c where c.age>:age");
query.setInteger("age",age);
query.setCacheable(true);
有很多人认为Hibernate天生效率比较低,确实,在普遍情况下,需要将执行转换为SQL语句的Hibernate的效率低于直接JDBC存取,然而,在经过比较好的性能优化之后,Hibernate的性能还是让人相当满意的,特别是应用二级缓存之后,甚至可以获得比较不使用缓存的JDBC更好的性能,下面介绍一些通常的Hibernate的优化策略:
1.抓取优化
抓取是指Hibernate如何在关联关系之间进行导航的时候,Hibernate如何获取关联对象的策略,其主要定义了两个方面:如何抓取和何时抓取
1)如何抓取。
Hibernate3主要有两种种抓取方式,分别应用于对象关联实例(many-to-one、one-to-one)和对象关联集合(set、map等),总共是四种变种
JOIN抓取: 通过在SELECT语句中使用OUTER JOIN来获得对象的关联实例或者关联集合)
SELECT抓取: 另外发送一条SELECT语句来抓取当前对象的关联实体和集合
在我的开发经历中,此处对性能的优化是比较有限的,并不值得过多关注
例:
A.应用于对象关联实例(默认是false)
<many-to-one name=".." outer-join="true/false/auto" .../>
B.应用于对象关联集合(默认是auto)
<set name=".." fetch="join/select" ... >
....
</set>
2)何时抓取
主要分为延迟加载和立即抓取,默认的情况下Hibernate3对对象关联实采用延迟加载,普通属性采用立即抓取,通过延迟加载和采用适当的抓取粒度,与不采用优化相比往往可以将性能提升数倍
立即抓取:当抓取宿主对象时,同时抓取其关联对象和关联集以及属性
延迟加载:当抓取宿主对象时,并不抓取其关联对象,而是当对其对象进行调用时才加载
例:
A.应用于对象关联实例(默认是延迟加载)
<many-to-one name=".." lazy="true/false" .../>
B.应用于对象关联集合(默认是延迟加载)
<set name=".." lazy="true/false" ... >
....
</set>
对于延迟加载,需要注意的时,对延迟对象的使用必须在Session关闭之前进行,Hibernate的LazyInitalizationException往往就是由于在Session的生命期外使用了延迟加载的对象。当我们进行Web开发时,可以使用OpenSessionInView模式,当请求开始时打开session,当请求响应结束时才关闭session,不过,在使用OpenSessionInView模式时,需要注意如果响应时间比较长(业务比较复杂或者客户端是低速网络),将Session资源(也就是数据库的连接)占用太久的话可以会导致资源耗尽
3)抓取粒度
抓取粒度指的是对象在关联关系之间被导航时一次预先加载的数量,Hibernate程序的性能比较差往往就在于没有对抓取粒度仔细考虑,当加载一个列表并在列表中的每个对象中对其关联进行导航时,往往导致N+1条SQL语句查询。
例:
A.应用于对象关联实例(默认为1),注意,对对象关联实例的设置是在被关联的对象之上的,譬如
class User
{
Group g;
}
那么抓取粒度应该在Group的配置文件之上,见下
<class name="Group" table="group" batch-size="..">
...
</class>
对该值并没有一个约定俗成的值,根据情况而定,如果被关联表数据比较少,则可以设置地小一些,3-20,如果比较大则可以设到30-50,注意的时候,并不是越多越好,当其值超过50之后,对性能并没有多大改善但却无谓地消耗内存
假设有如下例子:
List<User> users = query.list();
如果有20个User,并对这20个User及其Group进行遍历,如果不设置batch-size(即batch-size="1"),则在最糟糕的情况
下,需要1 + 20条SQL语句,如果设置batch-size="10",则最好的情况下只需要1 + 2条SQL语句
B.应用于对象关联集合(默认为1)
<set name=".." batch-size="" ... >
....
</set>
2.二级缓存
Hibernate对数据的缓存包括两个级:一级缓存,在Session的级别上进行,主要是对象缓存,以其id为键保存对象,在Session的生命期间存在;二级缓存,在SessionFactory的级别上进行,有对象缓存和查询缓存,查询缓存以查询条件为键保存查询结果,在SessionFactory的生命期间存在。默认地,Hibernate只启用一级缓存,通过正确地使用二级缓存,往往可以获得意想不到的性能。
1)对象缓存:
当抓取一个对象之后,Hiberate将其以id为键缓存起来,当下次碰到抓取id相同的对象时,可以使用如下配置
方法1:在缓存对象上配置
<class ...>
<cache useage="read-only/write/...." regions="group" />
</class>
useage表示使用什么类型的缓存,譬如只读缓存、读写缓存等等(具体参见Hibernate参考指南),值得注意的时,有部分缓存在Hibernate的实现中不支持读写缓存,譬如JBossCache在Hibernate的实现中只是一种只读缓存,具体缓存实现对缓存类型的支持情况,可以参见org.hibernate.cache包
regions表示缓存分块,大部分的缓存实现往往对缓存进行分块,该部分是可选的,详细参见各缓存实现
方法2:在hibernate.cfg.xml中配置
<cache class=".." useage=".." regions=".."/>
我认为第二种更好,可以统一管理
2)查询缓存
查询时候将查询结果以查询条件为键保存起来,需要配置如下
A.在hibernate.cfg.xml中配置(启用查询缓存)
<property name="hibernate.cache.use_query_cache">true</property> (前面的属性名可参见常量
org.hibernate.cfg.Enviroment.USE_QUERY_CACHE)
B.程序
query.setCacheable(true);
query.setCacheRegions(...);
需要注意的是,查询缓存与对象缓存要结合更有效,因为查询缓存仅缓存查询结果列表的主键数据
一般情况下在开发中,对一些比较稳定而又被频繁引用的数据,譬如数据字典之类的,将其进行二级缓存,对一些查询条件和查询数据变化不频繁而又常常被使用的查询,将其进行二级缓存。由于二级缓存是放在内存中,而且Hibernate的缓存不是弱引用缓存(WeekReference),所以注意不要将大块的数据放入其中,否则可能会被内存造成比较大的压力。
3.批量数据操作
当进行大批量数据操作(几万甚至几十几百万)时,需要注意两点,一,批量提交,二,及时清除不需要的一级缓存数据
1)所谓的批量提交,就是不要频繁使用session的flush,每一次进行flush,Hibernate将PO数据于数据库进行同步,对于海量级数据操作来说是性能灾难(同时提交几千条数据和提交一条数据flush一次性能差别可能会是几十倍的差异)。一般将数据操作放在事务中,当事务提交时Hibernate自动帮你进行flush操作。
2)及时清除不需要的一级缓存数据:由于Hibernate默认采用一级缓存,而在session的生命期间,所有数据抓取之后会放入一级缓存中,而当数据规模比较庞大时,抓取到内存中的数据会让内存压力非常大,一般分批操作数据,被一次操作之后将一级缓存清除,譬如
session.clear(User.class)
4.杂项
dynamic-insert,dynamic-update,动态插入和动态更新,指的是让Hibernate插入数据时仅插入非空数据,当修改数据时只修改变化的数据,譬如对于
class User
{
id
username
password
}
如果u.id=1, u.username="ayufox",u.password=null,那么如果不设置动态插入,则其sql语句是insert into users(id, username, password) values (1, 'ayufox', '),如果设置则其sql语句是insert into users(username) valeus('ayufox')
在如上的情况下,如果修改u.password='11',那么如果不设置动态更新,则sql语句为update users set username='ayufox', password='11' where id = 1,如果设置则为update user set password='11' where d = 1
设置是在class的映射文件中,如下
<class name="User" table="users" dynamic=insert="true/false" dynamic-update="true/false" ...>
</class>
该设置对性能的提升比较有限
http://hi.baidu.com/jellywgd/blog/item/4b8cc380e6d4e7d19023d982.html
分享到:
相关推荐
### Hibernate性能优化研究 #### 一、引言 随着企业级应用的发展,高效的数据持久化技术成为了提升系统性能的关键因素之一。Hibernate作为一种流行的面向Java环境的对象关系映射(Object-Relational Mapping,简称...
珍藏的hibernate性能优化,如果对hibernate进行优化,很详细,是工作和面试的好助手
### Hibernate性能优化方案详解 #### 一、引言 Hibernate作为Java领域中广泛使用的对象关系映射(ORM)框架,其高效性和灵活性受到众多开发者的青睐。然而,不当的设计和配置往往会导致性能瓶颈,严重影响应用程序...
"Hibernate性能优化共9页.pdf.zip" 这个文件标题表明了内容专注于Hibernate框架的性能优化,暗示我们将探讨如何提升使用Hibernate进行数据库操作时的效率。通常,性能优化涉及减少延迟、提高吞吐量、降低资源消耗等...
Hibernate 性能优化 在 Hibernate 中,性能优化是非常重要的,因为它直接影响着应用程序的效率和可扩展性。在本文中,我们将讨论两个常见的性能优化问题:批量处理和 1+n 问题,并提供相应的解决方法。 问题 1:...
本文将深入探讨Hibernate性能优化中的一个重要概念——一级缓存,并结合给出的压缩包文件“hibernate_cache_level1”,来详细解析一级缓存的工作原理及其优化策略。 一级缓存是Hibernate内置的一种缓存机制,它存在...
以下是对《hibernate性能优化[参考].pdf》内容的详细解读: 1. **数据库优化**: - **物理硬件优化**:关注磁盘的IO性能,因为数据库读写频繁,磁盘的寻道能力直接影响数据访问速度。 - **MySQL配置优化**:通过...
### Hibernate 性能优化 #### 一、引言 Hibernate 是一款非常强大的对象关系映射(ORM)框架,它能够简化 Java 应用程序与数据库之间的交互过程。然而,对于初次接触 Hibernate 的开发者来说,可能会遇到性能方面...
二级缓存是Hibernate性能优化的重要手段,通过合理配置和使用,可以显著减少数据库访问,提高系统响应速度。但同时,需要注意缓存的副作用,如数据一致性、并发控制等问题。在实际应用中,需要结合业务场景和性能...
在进行大型项目开发时,性能优化是至关重要的,特别是对于基于SSH(Struts、Spring、Hibernate)这样的企业级框架的应用。SSH性能优化主要是针对Struts的MVC处理、Spring的依赖注入以及Hibernate的对象关系映射进行...
### Hibernate性能调优知识...综上所述,Hibernate性能优化涉及多个层面,包括但不限于关联管理、集合类型选择、继承关系配置以及缓存策略等。合理配置这些选项能够显著提高应用程序的性能,并且减少不必要的资源消耗。
【标签】:hibernate, 性能优化 【正文】: 1. **数据库设计调整**: - **降低关联的复杂性**:减少多对多关联,避免过度嵌套的对象关系。 - **避免联合主键**:联合主键可能导致额外的性能损失,尝试使用单独的...