Hibernate性能调优
1 Hibernate 连接池
hibernate自带一个连接池,但是这个连接池的性能不好,BUG也比较多,所以hibernate借助第三方的连接池来配置。通常用的比较多的是prxool。目前在j2ee中最通用的框架ssh中,hibernate的配置如下:
在spring 的applicationContext.xm.配置文件里配置数据源连接信息:
<!-- 配置数据源 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>org.logicalcobwebs.proxool.ProxoolDriver</value>
</property>
<property name="url">
<value>proxool.spring_user</value>
</property>
</bean>
在web.xml中做如下配置
<!-- 制定proxool.xml放置的位置 -->
<param-value>WEB-INF/proxool.xml</param-value>
</context-param>
<listener>
将proxool.xml连接池配置文件放入到工程里WEB-INF目录下,其中proxool.xml的内容如下:
<?xml version="1.0" encoding="utf-8"?>
<!-- the
proxool configuration can be embedded within your own application's.
Anything outside the "proxool" tag
is ignored. -->
<something-else-entirely>
<proxool>
<alias>spring_user</alias>
<driver-url>jdbc:mysql://192.168.1.150:3306/chiyuweb</driver-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<driver-properties>
<property name="user"
value="root" />
<property name="password"
value="123456" />
<property name="useUnicode"
value="true" />
<property name="characterEncoding"
value="GBK" />
</driver-properties>
<minimum-connection-count>5</minimum-connection-count> <maximum-connection-count>50</maximum-connection-count> <maximum-active-time>60000</maximum-active-time>
<house-keeping-test-sql>select 1</house-keeping-test-sql>
<prototype-count>5</prototype-count>
<house-keeping-sleep-time>60000</house-keeping-sleep-time>
</proxool>
</something-else-entirely>
注:在prxool这个文件里<alias>spring_user</alias> 表示连接的别名,一个连接池可以配置多个连接。
2 Hibernate 多条件分页查询
Hibernate的多条件查询的方法有很多种,比较常用的有两种,一种的创建Query对象,一种是创建Criteria对象。
Query对象查询:Hibernate上下文对象query= session.createQuery(HQL); query.setParameters(Object[]
params,Type[] types)返回一个根据参数查询的List集合。分页方法query.setFirstResult(START),START参数表示从查询到的结果集里第几条记录开始取query.setMaxResults(ROWS),ROWS表示分页信息中每页查询的记录条数。根据如上方法即可以实现hibernate多条件分页查询。其中query.setParameters方法的两个参数,params,types。他们是一一对应,成对出现的,所以最后用顺序表来保存他们的值,即两个用ArrayList来成对存储两个参数,然后将他们转化成数组。Type类型是org.hibernate中的Type类。如果参数是String类型,则参数需要设置成Hibernate.STRING,如他类型依次类推。时间类型需要注意如果比较精确到天,类型可设置成Hibernate.DATE,如果时间要精确到秒,则时间类型需要设置成Hibernate.TIMESTAMPS.
Criteria对象查询,调用session.createCriteria(Type
type).add() type是反射包里面的Type ,(若查User类 ,则传入User.class),add()方法能够传入字段的名称 addOrder方法能够传入排序规则,如此实现多条件查询。分页方法同query。
3
Hibernate关联关系
Hibernate通常用的关联关系有三种:一对一,一对多和多对多。
一对一的方式有两种:一种是联合主键;一种是通过其他列来关联,即多对一的特殊形式,将多对一unique属性设置为true。配置方法网上都有这里就不啰嗦。
多对多关系并不提倡用many-to-many方式来配,通常用两个一对多的关系来实现。
一对多关系,这个关系的配的时候要特别注意,在多的一方<many-to-one/> 这边的lazy属性一般不要设置为false。这样配会大大的降低程序的性能。还有就是关联的列最好不要设置成外键关系,以为这样做加了外键会使数据库不易维护。关联列单独设置,在实体配置文件中这个列的约束这样设置 insert=”false” update=”false” 即可。
对于一对多自连接关系举一个实例来说明:
比如一个Person类里有老师和学生的关系
则Person.hbm.xml配置如下
<property name=”teacher_id” type=”java.lang.Integer” insert=”false” update=”false” />
<set name="students" cascade="save-update" inverse="true" lazy="true">
<key column="teacher_id" />
<one-to-many class="Person" />
</set>
<many-to-one
name="student" column="teacher_id"
class="Person" cascade="save-update"
/>
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)