Hibernate性能优化策略(二)
缓存机制缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。缓存内的数据是对物理数据源中数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。
Hibernate的缓存包括Session的缓存和SessionFactory的缓存,成为第一级缓存和二级缓存,这两级缓存都位于持久化层,存放的都是数据库数据的拷贝。
一级缓存
一级缓存生命周期很短和session的生命周期一致,一级缓存也叫session级的缓存或事务级缓存,在同一个Session中,它缓存的是实体对象,支持一级缓存的方法有load/get/iterate和save(同一个Session中先save后load不会发sql),但一级缓存是不会缓存普通属性的。
在一级缓存中进行大批量数据添加时,要注意缓存溢出的情况,每添加数条数据要及时清理缓存,示例代码如下:
[java] view plaincopy
/**
* 大批量的数据添加
*/
public void testCache7() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
for (int i=0; i<100; i++) {
Student student = new Student();
student.setName("张三" + i);
session.save(student);
//每20条更新一次
if (i % 20 == 0) {
session.flush();
//清除缓存的内容
session.clear();
}
}
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
二级缓存
二级缓存也称为进程级的缓存或SessionFactory级的缓存,二级缓存可以被所有的session共享,二级缓存的生命周期和SessionFactory的生命周期一致,SessionFactory可以管理二级缓存,二级缓存一般使用第三方的缓存产品,Hibernate文档推荐了几种:Hashtable(Hibernate内部,只做测试用)、EHCache、OSCache、SwarmCache、JBossTreeCache。
以EHCache为例,二级缓存的的配置和使用:
1. 将ehcache.xml文件拷贝到src下;
2. 在hibernate.cfg.xml文件中加入缓存产品提供商<propertyname="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>;
3. 启用二级缓存,这也是它的默认配置<propertyname="hibernate.cache.use_second_level_cache">true</property>;
4. 指定哪些实体类使用二级缓存
可以在映射文件中采用<cache>标签指定或在hibernate.cfg.xml文件中统一指定,注意使用的策略,通常采用read-only和read-write;
缓存原则:通常读远远大于写的数据进行缓存。
一级缓存和二级缓存的交互中,可以通过一级缓存中的方法session.setCacheMode(CacheMode.IGNORE)禁止数据放到二级缓存中。在讲一级缓存大批量数据添加时,为了防止缓存溢出要随时清理一级缓存,但是如果配置了二级缓存,如果不禁止二级缓存,同样会引发缓存溢出而出错,因此需要禁止一级缓存和二级缓存的交互。
查询缓存
查询缓存是缓存普通属性结果集,可以对实体对象的结果集缓存id,查询缓存的生命周期,当关联的表发生修改,查询缓存的生命周期结束,查询缓存和session的生命周期是无关的,可以跨Session。查询缓存只对query.list()起作用,query.iterate()查询普通属性不会使用查询缓存。
查询缓存的配置和使用:
1. 修改hibernate.cfg.xml文件,来开启查询缓存,默认是false是不起用的<propertyname="hibernate.cache.use_query_cache">true</property>
2. 必须在程序启用 query.setCacheable(true)
锁机制
其实,把锁写进Hibernate优化里是有些问题的,本身加锁是对性能极大的损耗,但鉴于有些时候我们不得不出于解决并发性问题而考虑加锁时,就产生了性能优化方面的思考,在此我们可以选择悲观锁和乐观锁,二者对性能的影响是不同的,因此合理选锁也会提升Hibernate的性能。
悲观锁
悲观锁,通常是由数据库机制实现的,在整个过程中把数据锁住(查询时),只要事务不释放(提交/回滚),那么任何用户都不能查看或修改。
只需在load方法中加入第三个参数LockMode.UPGRADE即可。还有:
LockMode.NONE:无锁机制。
LockMode.WRITE:Hibernate在Insert和Update记录的时候会自动获取。
LockMode.READ:Hibernate在读取记录的时候会自动获取。
以上这三种锁机制一般由Hibernate内部使用,如Hibernate为了保证Update过程中对象不会被外界修改,会在save方法实现中自动为目标对象加上WRITE锁。
LockMode.UPGRADE:利用数据库的forupdate子句加锁。
LockMode.UPGRADE_NOWAIT:Oracle的特定实现,利用Oracle的for update nowait子句实现加锁。
乐观锁
乐观锁,大多数的使用是采用数据版本的方式(version)实现,一般在数据库中加入一个version字段,在读取数据的时候将version读取出来,在保存数据的时候判断version的值是否小于数据库中的version值,如果小于不予更新,否则给予更新。
Hibernate中在class标签中通过属性optimistic-lock=”version”来描述,optimistic-lock属性可选取值:
none:无乐观锁。
version:通过版本机制实现乐观锁。
dirty:通过检查发生变动过的属性实现乐观锁。
all:通过检查所有属性实现乐观锁。
其中通过version实现的乐观锁机制是Hibernate官方推荐的乐观锁实现,同时也是Hibernate中,目前唯一在数据对象脱离Session发生修改的情况下依然有效
作者:StubbornPotatoes
补充:软件开发 , Java ,