Hibernate一级缓存
Hibernate的一级缓存是由Session提供的,因此它只存在于Session的生命周期中,当程序调用save(),update(),saveorupdate()等方法及调用查询接口list,filter,iterate时,如session缓存中还不存在相应的对象,Hibernate会把该对象加入到一级缓存中,
当Session关闭的时候该Session所管理的一级缓存也会立即被清除
Hibernate的一级缓存是Session所内置的,不能被卸载,也不能进行任何配置
一级缓存采用的是key-value的Map方式来实现的,在缓存实体对象时,对象的主关键字ID是Map的key,实体对象就是对应的值。所以说,一级缓存是以实体对象为单位进行存储的,在访问的时候使用的是主关键字ID
虽然,Hibernate对一级缓存使用的是自动维护的功能,没有提供任何配置功能,但是可以通过Session中所提供的方法来对一级缓存的管理进行手工干预。Session中所提供的干预方法包括以下两种
●evict() :用于将某个对象从Session的一级缓存中清除
evict()方法适用于以下二种情况:
1)不需要该对象进行同步的数据更新
2)在批量进行更新与删除时,当更新删除每一个对象后,要释对此对象所占用的内存.
●clear() :用于将一级缓存中的所有对象全部清除。</p>
在进行大批量数据一次性更新的时候,会占用非常多的内存来缓存被更新的对象。
这时就应该阶段性地调用clear()方法来清空一级缓存中的对象,控制一级缓存的大小,以避免产生内存溢出的情况。
Hibernate大批量更新时缓存的处理方法:
(假设我们user表的age有5000条大于0的记录,)
Session session =SessionFactory.openSession();
Transaction tx =session.beginTransaction();
int count = 0;
Itertaor users=session.find("from User u where u.age>0").itertaor();
while(user.hasNext()){
User user =(User)users.next();
user.setAge(user.getAge()+1);
//将本批插入的对象立即写入数据库并释放内存
if(count%30==0){
session.flush();
session.clear();
}
count++;
}
tx.commit();
session.close();
用Hibernate处理大批数据时..都必须先执行5000次的update语句,然后才能更新5000个user 对象..
这样就影响到了操作上的性能....在项目当我们遇到性能与空间的问题时,,,要以性能为主..这也就是说要牺牲空间
所以程序最好跳过Hibernate API 而直接通过JDBC API来执来...
我们改一下上面的代码:
Session session=SessionFactory.openSession();
Transaction tx =session.beginTransaction();
Connection conn =session.connection();
PreparedStatement pstmt = conn.prepareStatement("update users set age=age+1 "+"where age >0");
pstmt.executeUpdate();
tx.commit();
虽说这是通过JDBC API搞作的..但本质上还是通过Hibernater Transaction的事务这个接口来声明事务的边界的...
其实最好的解决方法就是以创建存储过程,,用底层的数据库运行..这样性能好,速度快....
我就简单的以Oracle数据库为例子.创建一个名为UserUpdate的存储过程...然后在程序中进行调用...
UserUpdate的存储过程代码:
create or replace procadure UserUpdate(u_age in number) as
begin
update users set age=age+1 where age>u_age;
end;
下面的是在程序中如何调用我们命名的存储过程
Session session =SessionFactory.openSession();
Transaction tx =session.beginTransaction();
Connection conn=session.connection();
String str="{call UserUpdate(?)}";
CallableStatement cstmt= conn.prepareCall(str);
cstmt.setInt(1,0);
cstmt.executeUpdate();
tx.commit();
用JDBC API的好处是这样的..
它不用把大批量的数据事先加载到内存中,然后再进行更新与修改..所以不会消耗大量内存....
(小程序中是看不出什么差别的,当数据的记录达到一定的数据量的时候自然会发现用Hibernate API 与JDBC API的差别)
在一个就是只能一条记录进行批量更新..不像Hibernate中更新每一条的..
hibernate二级缓存
启用Hibernate二级缓存
Hibernate二级缓存分为两部分,class缓存和查询缓存,其获取对象的方式有所不同,但两者也有联系,查询缓存必须以class缓存为基础才能起作用,否则只会使效率更低。
我们这里使用的二级缓存是通过ehcache第三方插件实现的。
(一)配置Hibernate.cfg.xml
启用class缓存:
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
启用查询缓存:
<property name="hibernate.cache.use_query_cache">true</property>
(二)配置Spring框架中的hibernate
启用class缓存:
<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
启用查询缓存:
<prop key="hibernate.cache.use_query_cache">true</prop>
(三)配置ehcache
Ehcache配置文件为ehcache.xml,默认配置为:
<ehcache>
<diskStore path="java.io.tmpdir"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
overflowToDisk="true"/>
</ehcache>
其中各项内容的含义为:
diskStore:代表当二级缓存对象数量超过maxElementsInMemory时,如果需要写入文件系统时的文件目录。
defaultCache:默认的calss缓存配置,如果某个对象没有其专有的配置时,ehcache一律启用默认配置。
maxElementInMemory:对象在内存中可存放的最大数量。
eternal:表示对象永不过期,如果选true则timeToIdleSeconds,timeToLiveSeconds两项无效。
timeToIdleSeconds:对象的空闲状态过期时间,单位为秒,0为可以无限制空闲。
timeToLiveSeconds:对象存在的最长时间,单位为秒(如果该项比timeToIdleSeconds要小,timeToIdleSeconds无意义),0为永不过期。
overflowToDisk:当对象在内存中的数量超过maxElementInMemory值时,如果该项为true,则ehcahe会把对象数据写入diskStore项指定的目录。
如果需要对某个具体对象进行单独配置时,可以加上一组cache配置,例如:
<cache name="com.juyee.mp.bean.SysCodelist"
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="1800"
timeToLiveSeconds="0"
overflowToDisk="true"
/>
另外还有两个特殊的cache配置:
<cache name="org.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000"
eternal="true"
timeToIdleSeconds="1800"
timeToLiveSeconds="0"
overflowToDisk="true"/>
<cache name="org.hibernate.cache.StandardQueryCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="0"
overflowToDisk="true"/>
这两个cache配置对应查询缓存,具体作用如下:
"当hibernate更新数据库的时候,它怎么知道更新哪些查询缓存呢? hibernate在一个地方维护每个表的最后更新时间,其实也就是放在上面UpdateTimestampsCache所指定的缓存配置里面。
当通过hibernate更新的时候,hibernate会知道这次更新影响了哪些表。然后它更新这些表的最后更新时间。每个缓存都有一个生成时间和这个缓存所查询的表,当hibernate查询一个缓存是否存在的时候,如果缓存存在,它还要取出缓存的生成时间和这个缓存所查询的表,然后去查找这些表的最后更新时间,如果有一个表在生成时间后更新过了,那么这个缓存是无效的。
可以看出,只要更新过一个表,那么凡是涉及到这个表的查询缓存就失效了,因此查询缓存的命中率可能会比较低"
当然,如果没有这两个配置,则ehcache将为查询缓存启用默认配置。
如何使用class缓存
对象缓存
Class缓存的作用主要是在内存中保存某个具体对象,当用户第一次通过get、iterator方式取出对象时,系统会先从class缓存中去找,如果没有再通过sql语句去数据库中查找相关记录,并将查询到的对象放入内存中。
实例:对某个对象使用二级缓存,只需要在该对象的hbm文件中配置即可
<cache usage="read-write"/>
我们注意到其中usage这个选项,它有多个选择,对应不同的含义,经常有这两种种:
read-only:只对缓存中的对象进行读操作。
read-write:当对象被update时,缓存中和数据库中一同被修改(缓存不支持事务回滚)。
2.2关联缓存
目前我们仅仅实现了对一个对象的缓存,那如何对该对象的关联对象集合进行缓存呢?
实例:对某个对象的关联对象集合的二级缓存,需要在该对象的hbm文件中set配置进行修改
<set name="children" lazy="true" order-by="treeid asc">
<cache usage="read-write"/>
<key column="PARENTID"/>
<one-to-many class="SysCodelist"/>
</set>
注意:
只对one-to-many有效,而且仅仅缓存的是关联对象的id集合,如果需要实现完全缓存,则需要对关联的对象也配置成使用二级缓存。
集合缓存是独立的,不受关联对象添加、删除的影响,如果要修改集合内容,必须对这个集合本身进行修改,
例如:codelist.getChildren().add()。
如何使用查询缓存
查询缓存,目的是为了将通过list()方法的查询结果存入缓存中,并实现对语句的缓存,如果下次用户在使用这条语句进行查询时,将直接从缓存中获取对象数据。
这里要注意的是,查询缓存必须配合class缓存使用,如果只启用查询缓存,不对查询对象启用二级缓存,则会大大降低查询效率。
因为,当第一次通过启用查询缓存的session进行语句查询时,系统只执行一次数据库查询将所有的记录取出,并将对象存入class缓存,语句及id集合存入查询缓存;而当用户第二次查询该语句时,系统将先执行去查询缓存中查找,取出所有符合条件的id集合,如果这时候该对象的class缓存没启用或在class缓存中已过期,系统将根据id,一个个去数据库load,实际上是进行了1+N次查询。
实际上,在我们系统中,并不是对所有对象都要进行二级缓存,而spring框架中提供的hibernate方法,虽然有getHibernateTemplate().setCacheQueries(),但该方法影响的是全局的配置,一旦启用,将会对不需要缓存的查询造成不良影响。
于是,我自己在hibernateService()中添加了一个方法:
public List findByCachedQuery(final String hql)
{
return (List) getHibernateTemplate().execute(new HibernateCallback() {
public Object doInHibernate(Session session) throws HibernateException {
Query queryObject = session.createQuery(hql);
queryObject.setCacheable(true);
if (getHibernateTemplate().getQueryCacheRegion() != null) {
queryObject.setCacheRegion(getHibernateTemplate().getQueryCacheRegion());
}
return queryObject.list();
}
}, true);
}
这样,将只在session范围内启用查询缓存,一旦该session结束了,那么查询缓存也将回复默认配置。
注意:使用时只支持hql。
http://nauu.iteye.com/blog/197212
分享到:
相关推荐
**Hibernate缓存深入详解** 在Java企业级应用开发中,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。然而,随着应用规模的扩大,数据访问性能成为了一个不可忽视的问题。这时,...
### Hibernate缓存技术研究 #### 一、引言 Hibernate是一种强大的对象-关系映射(Object-Relational Mapping,简称ORM)工具,主要用于Java环境下的应用程序。它能够将应用程序中的对象模型映射到关系型数据库的表...
Hibernate缓存.docHibernate缓存.doc
Java Hibernate缓存深入详解
**标题:“Hibernate缓存与Spring事务详解”** 在IT领域,尤其是Java开发中,Hibernate作为一款流行的ORM(对象关系映射)框架,极大地简化了数据库操作。而Spring框架则以其全面的功能,包括依赖注入、AOP(面向切...
Hibernate缓存机制是提高应用程序性能的关键技术之一,它通过存储数据副本减少对物理数据库的访问。缓存可以分为两层:第一级缓存和第二级缓存。 **第一级缓存**是内置在Session中的,它是不可卸载的,也称为...
关于hibernate缓存的一个ppt课件,60+幻灯片,有需要的可以看一下
【Hibernate缓存深入详解】 在Java的持久化框架Hibernate中,缓存机制是提升系统性能的关键因素。它位于Hibernate应用和数据库之间,减少了对数据库的直接访问,从而提高了应用程序的运行速度。缓存中存储的是...
**Hibernate缓存详解** 在Java开发中,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。为了提高数据访问性能,Hibernate引入了缓存机制,它可以减少对数据库的直接访问,从而提升应用的...
本文将深入探讨Hibernate缓存的原理、类型及其对性能优化的影响。 ### Hibernate缓存原理 Hibernate缓存主要分为一级缓存和二级缓存。一级缓存,也称为会话缓存(Session Cache),是默认启用的,由Hibernate自动...
Hibernate 是一个流行的对象关系映射(ORM)框架,它允许Java...通过理解Hibernate缓存和事务管理,以及如何有效地执行查询,开发者可以创建高效、健壮的Java应用程序,降低与数据库交互的复杂性,同时提升系统性能。
**标题解析:** "Hibernate教程25_Hibernate缓存" 这个标题表明了我们要讨论的是关于Hibernate框架的第25个教程,重点是它的缓存机制。Hibernate是一个流行的Java对象关系映射(ORM)框架,它允许开发者用面向对象的...
【Hibernate缓存管理】是数据库持久化框架Hibernate中优化性能的关键技术。缓存的主要目的是减少对数据库的直接访问,提高应用程序的运行效率。缓存的数据是数据库中数据的副本,存在于内存或硬盘中,便于快速读取。...
这篇博客文章“hibernate缓存ehcache用法”可能详细介绍了如何在Hibernate中配置和使用Ehcache。 首先,我们需要理解什么是缓存。缓存是一种存储技术,用于临时保存经常访问的数据,以减少对主存储器(如数据库)的...
【Hibernate缓存详解】 在Java开发中,Hibernate作为一款强大的对象关系映射(ORM)框架,极大地简化了数据库操作。其缓存机制是提升系统性能的关键所在。本篇将深入探讨Hibernate的缓存机制,包括一级缓存和二级...