- 浏览: 213192 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
strong8808:
activemq5.8.0 客户端,服务端启动序列图 -
xurichusheng:
第一题,如果使用 not exists 的话,可以改成:SEL ...
SQL笔试题 -
dingjun1:
cuisuqiang 写道如何解决呢?我的是对了也照样缓存增加 ...
事务未正确关闭引起的HIBERNATE SESSION不能正确关闭 -
dingjun1:
aijezdm915 写道lz ,我也是在写项目描述是犯愁,能 ...
如果在简历中描述项目 -
aijezdm915:
lz ,我也是在写项目描述是犯愁,能否给个你的简历demo,我 ...
如果在简历中描述项目
这部分为转载:http://www.iteye.com/topic/18904
很多人对二级缓存都不太了解,或者是有错误的认识,我一直想写一篇文章介绍一下hibernate的二级缓存的,今天终于忍不住了。
我的经验主要来自hibernate2.1版本,基本原理和3.0、3.1是一样的,请原谅我的顽固不化。
hibernate的session提供了一级缓存,每个session,对同一个id进行两次load,不会发送两条sql给数据库,但是session关闭的时候,一级缓存就失效了。
二级缓存是SessionFactory级别的全局缓存,它底下可以使用不同的缓存类库,比如ehcache、oscache等,需要设置hibernate.cache.provider_class,我们这里用ehcache,在2.1中就是
hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider
如果使用查询缓存,加上
hibernate.cache.use_query_cache=true
缓存可以简单的看成一个Map,通过key在缓存里面找value。
Class的缓存
对于一条记录,也就是一个PO来说,是根据ID来找的,缓存的key就是ID,value是POJO。无论list,load还是 iterate,只要读出一个对象,都会填充缓存。但是list不会使用缓存,而iterate会先取数据库select id出来,然后一个id一个id的load,如果在缓存里面有,就从缓存取,没有的话就去数据库load。假设是读写缓存,需要设置:
<cache usage="read-write"/>
如果你使用的二级缓存实现是ehcache的话,需要配置ehcache.xml
<cache name="com.xxx.pojo.Foo" maxElementsInMemory="500" eternal="false" timeToLiveSeconds="7200" timeToIdleSeconds="3600" overflowToDisk="true" />
其中eternal表示缓存是不是永远不超时,timeToLiveSeconds是缓存中每个元素(这里也就是一个POJO)的超时时间,如果eternal="false",超过指定的时间,这个元素就被移走了。timeToIdleSeconds是发呆时间,是可选的。当往缓存里面put 的元素超过500个时,如果overflowToDisk="true",就会把缓存中的部分数据保存在硬盘上的临时文件里面。
每个需要缓存的class都要这样配置。如果你没有配置,hibernate会在启动的时候警告你,然后使用defaultCache的配置,这样多个class会共享一个配置。
当某个ID通过hibernate修改时,hibernate会知道,于是移除缓存。
这样大家可能会想,同样的查询条件,第一次先list,第二次再iterate,就可以使用到缓存了。实际上这是很难的,因为你无法判断什么时候是第一次,而且每次查询的条件通常是不一样的,假如数据库里面有100条记录,id从1到100,第一次list的时候出了前50个id,第二次 iterate的时候却查询到30至70号id,那么30-50是从缓存里面取的,51到70是从数据库取的,共发送1+20条sql。所以我一直认为 iterate没有什么用,总是会有1+N的问题。
(题外话:有说法说大型查询用list会把整个结果集装入内存,很慢,而iterate只select id比较好,但是大型查询总是要分页查的,谁也不会真的把整个结果集装进来,假如一页20条的话,iterate共需要执行21条语句,list虽然选择若干字段,比iterate第一条select id语句慢一些,但只有一条语句,不装入整个结果集hibernate还会根据数据库方言做优化,比如使用mysql的limit,整体看来应该还是 list快。)
如果想要对list或者iterate查询的结果缓存,就要用到查询缓存了
查询缓存
首先需要配置hibernate.cache.use_query_cache=true
如果用ehcache,配置ehcache.xml,注意hibernate3.0以后不是net.sf的包名了
<cache name="net.sf.hibernate.cache.StandardQueryCache"
maxElementsInMemory="50" eternal="false" timeToIdleSeconds="3600"
timeToLiveSeconds="7200" overflowToDisk="true"/>
<cache name="net.sf.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000" eternal="true" overflowToDisk="true"/>
然后
query.setCacheable(true);//激活查询缓存
query.setCacheRegion("myCacheRegion");//指定要使用的cacheRegion,可选
第二行指定要使用的cacheRegion是myCacheRegion,即你可以给每个查询缓存做一个单独的配置,使用setCacheRegion来做这个指定,需要在ehcache.xml里面配置它:
<cache name="myCacheRegion" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200" overflowToDisk="true" />
如果省略第二行,不设置cacheRegion的话,那么会使用上面提到的标准查询缓存的配置,也就是net.sf.hibernate.cache.StandardQueryCache
对于查询缓存来说,缓存的key是根据hql生成的sql,再加上参数,分页等信息(可以通过日志输出看到,不过它的输出不是很可读,最好改一下它的代码)。
比如hql:
from Cat c where c.name like ?
生成大致如下的sql:
select * from cat c where c.name like ?
参数是"tiger%",那么查询缓存的key*大约*是这样的字符串(我是凭记忆写的,并不精确,不过看了也该明白了):
select * from cat c where c.name like ? , parameter:tiger%
这样,保证了同样的查询、同样的参数等条件下具有一样的key。
现在说说缓存的value,如果是list方式的话,value在这里并不是整个结果集,而是查询出来的这一串ID。也就是说,不管是list方法还是iterate方法,第一次查询的时候,它们的查询方式很它们平时的方式是一样的,list执行一条sql,iterate执行1+N条,多出来的行为是它们填充了缓存。但是到同样条件第二次查询的时候,就都和iterate的行为一样了,根据缓存的key去缓存里面查到了value,value是一串id,然后在到class的缓存里面去一个一个的load出来。这样做是为了节约内存。
可以看出来,查询缓存需要打开相关类的class缓存。list和iterate方法第一次执行的时候,都是既填充查询缓存又填充class缓存的。
这里还有一个很容易被忽视的重要问题,即打开查询缓存以后,即使是list方法也可能遇到1+N的问题!相同条件第一次list的时候,因为查询缓存中找不到,不管class缓存是否存在数据,总是发送一条sql语句到数据库获取全部数据,然后填充查询缓存和 class缓存。但是第二次执行的时候,问题就来了,如果你的class缓存的超时时间比较短,现在class缓存都超时了,但是查询缓存还在,那么 list方法在获取id串以后,将会一个一个去数据库load!因此,class缓存的超时时间一定不能短于查询缓存设置的超时时间!如果还设置了发呆时间的话,保证class缓存的发呆时间也大于查询的缓存的生存时间。这里还有其他情况,比如class缓存被程序强制evict了,这种情况就请自己注意了。
另外,如果hql查询包含select字句,那么查询缓存里面的value就是整个结果集了。
当hibernate更新数据库的时候,它怎么知道更新哪些查询缓存呢?
hibernate在一个地方维护每个表的最后更新时间,其实也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的缓存配置里面。
当通过hibernate更新的时候,hibernate会知道这次更新影响了哪些表。然后它更新这些表的最后更新时间。每个缓存都有一个生成时间和这个缓存所查询的表,当hibernate查询一个缓存是否存在的时候,如果缓存存在,它还要取出缓存的生成时间和这个缓存所查询的表,然后去查找这些表的最后更新时间,如果有一个表在生成时间后更新过了,那么这个缓存是无效的。
可以看出,只要更新过一个表,那么凡是涉及到这个表的查询缓存就失效了,因此查询缓存的命中率可能会比较低。
Collection缓存
需要在hbm的collection里面设置
<cache usage="read-write"/>
假如class是Cat,collection叫children,那么ehcache里面配置
<cache name="com.xxx.pojo.Cat.children"
maxElementsInMemory="20" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200"
overflowToDisk="true" />
Collection的缓存和前面查询缓存的list一样,也是只保持一串id,但它不会因为这个表更新过就失效,一个collection缓存仅在这个collection里面的元素有增删时才失效。
这样有一个问题,如果你的collection是根据某个字段排序的,当其中一个元素更新了该字段时,导致顺序改变时,collection缓存里面的顺序没有做更新。
缓存策略
只读缓存(read-only):没有什么好说的
读/写缓存(read-write):程序可能要的更新数据
不严格的读/写缓存(nonstrict-read-write):需要更新数据,但是两个事务更新同一条记录的可能性很小,性能比读写缓存好
事务缓存(transactional):缓存支持事务,发生异常的时候,缓存也能够回滚,只支持jta环境,这个我没有怎么研究过
读写缓存和不严格读写缓存在实现上的区别在于,读写缓存更新缓存的时候会把缓存里面的数据换成一个锁,其他事务如果去取相应的缓存数据,发现被锁住了,然后就直接取数据库查询。
在hibernate2.1的ehcache实现中,如果锁住部分缓存的事务发生了异常,那么缓存会一直被锁住,直到60秒后超时。
不严格读写缓存不锁定缓存中的数据。
使用二级缓存的前置条件
你的hibernate程序对数据库有独占的写访问权,其他的进程更新了数据库,hibernate是不可能知道的。你操作数据库必需直接通过 hibernate,如果你调用存储过程,或者自己使用jdbc更新数据库,hibernate也是不知道的。hibernate3.0的大批量更新和删除是不更新二级缓存的,但是据说3.1已经解决了这个问题。
这个限制相当的棘手,有时候hibernate做批量更新、删除很慢,但是你却不能自己写jdbc来优化,很郁闷吧。
SessionFactory也提供了移除缓存的方法,你一定要自己写一些JDBC的话,可以调用这些方法移除缓存,这些方法是:
void evict(Class persistentClass)
Evict all entries from the second-level cache.
void evict(Class persistentClass, Serializable id)
Evict an entry from the second-level cache.
void evictCollection(String roleName)
Evict all entries from the second-level cache.
void evictCollection(String roleName, Serializable id)
Evict an entry from the second-level cache.
void evictQueries()
Evict any query result sets cached in the default query cache region.
void evictQueries(String cacheRegion)
Evict any query result sets cached in the named query cache region.
不过我不建议这样做,因为这样很难维护。比如你现在用JDBC批量更新了某个表,有3个查询缓存会用到这个表,用evictQueries (String cacheRegion)移除了3个查询缓存,然后用evict(Class persistentClass)移除了class缓存,看上去好像完整了。不过哪天你添加了一个相关查询缓存,可能会忘记更新这里的移除代码。如果你的 jdbc代码到处都是,在你添加一个查询缓存的时候,还知道其他什么地方也要做相应的改动吗?
以上部分为转载
//////=======================================================
以下为翻译
hibernate 缓存
Cache mappings
类或者集合映射的<CACHE>元素为下面的格式:
<cache
usage="transactional|read-write|nonstrict-read-write|read-only" (1)
region="RegionName" (2)
include="all|non-lazy" (3)
/>
(1) usage (必须) 详细指明缓存的策略:事务级,读-写,非严格读写,只读。
(2) region (可选,默认为类名或者为集合的角色名称) 详细说明两级缓存区域的名称
(3) include (可选,默认为all) non-lazy详细指明在属性级的延迟加载使用使用fetch激活时,使用lazy="true"的实体映射属性可能不会被缓存
19.2.2. Strategy: read only
如果你的应用中只需要读,而从不修改持久类的实例,只读级策略的缓存可能被使用,这是最简单性能最好的策略,在集群中使用是十分安全的(前提是数据不会被修改)。
<class name="eg.Immutable" mutable="false">
<cache usage="read-only"/>
....
</class>
19.2.3. Strategy: read/write
如果你的应用需要更新数据,读写缓存可能比较合适,当要求序列化隔离事务级时,这种缓存策略不应该使用,如果缓存是在JTA环境下,你必须指明
hibernate.transaction.manager_lookup_class属性的值,命名包含在JTA 事务管理下的策略,在其它的环境中,你必须确保在session.close()或者调用session.disconnect()前
,事务全部完成。如果使用这种策略在集群中,必须确保底层的缓存实现支持锁,内嵌提供的缓存不支持。
<class name="eg.Cat" .... >
<cache usage="read-write"/>
....
<set name="kittens" ... >
<cache usage="read-write"/>
....
</set>
</class>
19.2.4. Strategy: nonstrict read/write
如果应用只是偶尔需要更新数据(例如,几乎不可能两个事务会试图同一时间修改同一条记录),不需要严格的事务隔离,非严格读写缓存是合适的,如果在JTA环境中使用缓存,
需要详细指明hibernate.transaction.manager_lookup_class,在其它的环境中,应该确保有事务在session.close()或者Session.disconnect()被调用前完成。
19.2.5. Strategy: transactional
事务级缓存策略支持像JBOSS TreeCache这样的事务级缓存提供者,如果在JTA环境中必须指明hibernate.transaction.manager_lookup_class.
19.3. Managing the caches
无论你传递一个对象去save(),update() 或者saveOrUpdate(),还是你使用load(),get(),list(),iterate()or scroll(),重新取回一个对象,这个对象都会被添加到session的缓存
中。当随后调用flush()时,对象的状态会与数据库同步,如果你不想让这个同步发生,或者你正在处理一个巨大数量的对象,需要有效管理内存,使用evict()从session缓存中移
除这些对象和它们的集合。
ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
while ( cats.next() ) {
Cat cat = (Cat) cats.get(0);
doSomethingWithACat(cat);
sess.evict(cat);
}
Session也提供了一个contains()方法去确认一个对象是否属于这个session缓存。
调用Session.clear()可以从session 缓存中完全驱逐所有的对象。
为二级缓存,SessionFactory有驱逐处于缓存状态的实例,整个类,集合实例,或者整个集合角色的方法
sessionFactory.evict(Cat.class, catId); //evict a particular Cat
sessionFactory.evict(Cat.class); //evict all Cats
sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections
The CacheMode controls how a particular session interacts with the second-level cache.
CacheMode.NORMAL - read items from and write items to the second-level cache
CacheMode.GET - read items from the second-level cache, but don't write to the second-level cache except when updating data
CacheMode.PUT - write items to the second-level cache, but don't read from the second-level cache
CacheMode.REFRESH - write items to the second-level cache, but don't read from the second-level cache, bypass the effect of hibernate.cache.use_minimal_puts,
forcing a refresh of the second-level cache for all items read from the database
To browse the contents of a second-level or query cache region, use the Statistics API:
Map cacheEntries = sessionFactory.getStatistics()
.getSecondLevelCacheStatistics(regionName)
.getEntries();
You'll need to enable statistics, and, optionally, force Hibernate to keep the cache entries in a more human-understandable format:
hibernate.generate_statistics true
hibernate.cache.use_structured_entries true
19.4. The Query Cache
查询结果集也可以被缓存,这仅仅对频繁运行使用相同参数的查询有用,必须首先激活查询缓存,才能使用查询缓存。
hibernate.cache.use_query_cache true
这个设置引发两个新的缓存区域的创建,一个控制缓存查询结果集,另一个控制最新修改查询表的时间戳。注意,查询缓存不会缓存在结果集中实际实体的状态;它仅仅缓存标识
值和结果值的类型,因此查询缓存常常与二级缓存联合使用。
大部分的查询操作不会从缓存中受益,默认查询不会被缓存,为了使缓存可用,调用Query.setCacheable(true).这个调用允许查询执行时寻找已经缓存的结果,或者添加结果到缓
存中。
如果你需要一个精细地控制查询缓存的方案,通过调用Query.setCacheRegion(),你可以为具体的查询指明缓存区域的名称.
List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
.setEntity("blogger", blogger)
.setMaxResults(15)
.setCacheable(true)
.setCacheRegion("frontpages")
.list();
如果查询想要刷新它查询的缓存区域,应该调用Query.setCacheMode(CacheMode.REFRESH)。当底层数据可能被单独的程序修改时,这是非常有用的。同时允许选择性地刷新具体的
查询结果集。有一个更有效率地清空查询缓存区域的作是通过sessionFactory.evictQueries()
//以下为实例部分
spring集成hibernate
1、管理SessionFactory
spring中对应的Bean类为org.springframework.orm.hibernate3.LocalSessionFactoryBean
配置文件:
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oralce:thin:@10.8.2.11:1521:hollycrm" />
<property name="username" value="system" />
<property name="password" value="system" />
<property name="maxActive" value="50" />
<property name="maxIdle" value="10" />
<property name="minIdle" value="5" />
<property name="maxWait" value="20000" />
<property name="removeAbandonedTimeout" value="120" />
<property name="removeAbandoned" value="true" />
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource" /><!-- 数据源 -->
<!--
-->
<property name="mappingResources">
<list>
<value>***.hbm.xml</value>
<value>.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect" >org.springframework.dialect.OracleDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
applicationContext.xml
ehcache.xml
很多人对二级缓存都不太了解,或者是有错误的认识,我一直想写一篇文章介绍一下hibernate的二级缓存的,今天终于忍不住了。
我的经验主要来自hibernate2.1版本,基本原理和3.0、3.1是一样的,请原谅我的顽固不化。
hibernate的session提供了一级缓存,每个session,对同一个id进行两次load,不会发送两条sql给数据库,但是session关闭的时候,一级缓存就失效了。
二级缓存是SessionFactory级别的全局缓存,它底下可以使用不同的缓存类库,比如ehcache、oscache等,需要设置hibernate.cache.provider_class,我们这里用ehcache,在2.1中就是
hibernate.cache.provider_class=net.sf.hibernate.cache.EhCacheProvider
如果使用查询缓存,加上
hibernate.cache.use_query_cache=true
缓存可以简单的看成一个Map,通过key在缓存里面找value。
Class的缓存
对于一条记录,也就是一个PO来说,是根据ID来找的,缓存的key就是ID,value是POJO。无论list,load还是 iterate,只要读出一个对象,都会填充缓存。但是list不会使用缓存,而iterate会先取数据库select id出来,然后一个id一个id的load,如果在缓存里面有,就从缓存取,没有的话就去数据库load。假设是读写缓存,需要设置:
<cache usage="read-write"/>
如果你使用的二级缓存实现是ehcache的话,需要配置ehcache.xml
<cache name="com.xxx.pojo.Foo" maxElementsInMemory="500" eternal="false" timeToLiveSeconds="7200" timeToIdleSeconds="3600" overflowToDisk="true" />
其中eternal表示缓存是不是永远不超时,timeToLiveSeconds是缓存中每个元素(这里也就是一个POJO)的超时时间,如果eternal="false",超过指定的时间,这个元素就被移走了。timeToIdleSeconds是发呆时间,是可选的。当往缓存里面put 的元素超过500个时,如果overflowToDisk="true",就会把缓存中的部分数据保存在硬盘上的临时文件里面。
每个需要缓存的class都要这样配置。如果你没有配置,hibernate会在启动的时候警告你,然后使用defaultCache的配置,这样多个class会共享一个配置。
当某个ID通过hibernate修改时,hibernate会知道,于是移除缓存。
这样大家可能会想,同样的查询条件,第一次先list,第二次再iterate,就可以使用到缓存了。实际上这是很难的,因为你无法判断什么时候是第一次,而且每次查询的条件通常是不一样的,假如数据库里面有100条记录,id从1到100,第一次list的时候出了前50个id,第二次 iterate的时候却查询到30至70号id,那么30-50是从缓存里面取的,51到70是从数据库取的,共发送1+20条sql。所以我一直认为 iterate没有什么用,总是会有1+N的问题。
(题外话:有说法说大型查询用list会把整个结果集装入内存,很慢,而iterate只select id比较好,但是大型查询总是要分页查的,谁也不会真的把整个结果集装进来,假如一页20条的话,iterate共需要执行21条语句,list虽然选择若干字段,比iterate第一条select id语句慢一些,但只有一条语句,不装入整个结果集hibernate还会根据数据库方言做优化,比如使用mysql的limit,整体看来应该还是 list快。)
如果想要对list或者iterate查询的结果缓存,就要用到查询缓存了
查询缓存
首先需要配置hibernate.cache.use_query_cache=true
如果用ehcache,配置ehcache.xml,注意hibernate3.0以后不是net.sf的包名了
<cache name="net.sf.hibernate.cache.StandardQueryCache"
maxElementsInMemory="50" eternal="false" timeToIdleSeconds="3600"
timeToLiveSeconds="7200" overflowToDisk="true"/>
<cache name="net.sf.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000" eternal="true" overflowToDisk="true"/>
然后
query.setCacheable(true);//激活查询缓存
query.setCacheRegion("myCacheRegion");//指定要使用的cacheRegion,可选
第二行指定要使用的cacheRegion是myCacheRegion,即你可以给每个查询缓存做一个单独的配置,使用setCacheRegion来做这个指定,需要在ehcache.xml里面配置它:
<cache name="myCacheRegion" maxElementsInMemory="10" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200" overflowToDisk="true" />
如果省略第二行,不设置cacheRegion的话,那么会使用上面提到的标准查询缓存的配置,也就是net.sf.hibernate.cache.StandardQueryCache
对于查询缓存来说,缓存的key是根据hql生成的sql,再加上参数,分页等信息(可以通过日志输出看到,不过它的输出不是很可读,最好改一下它的代码)。
比如hql:
from Cat c where c.name like ?
生成大致如下的sql:
select * from cat c where c.name like ?
参数是"tiger%",那么查询缓存的key*大约*是这样的字符串(我是凭记忆写的,并不精确,不过看了也该明白了):
select * from cat c where c.name like ? , parameter:tiger%
这样,保证了同样的查询、同样的参数等条件下具有一样的key。
现在说说缓存的value,如果是list方式的话,value在这里并不是整个结果集,而是查询出来的这一串ID。也就是说,不管是list方法还是iterate方法,第一次查询的时候,它们的查询方式很它们平时的方式是一样的,list执行一条sql,iterate执行1+N条,多出来的行为是它们填充了缓存。但是到同样条件第二次查询的时候,就都和iterate的行为一样了,根据缓存的key去缓存里面查到了value,value是一串id,然后在到class的缓存里面去一个一个的load出来。这样做是为了节约内存。
可以看出来,查询缓存需要打开相关类的class缓存。list和iterate方法第一次执行的时候,都是既填充查询缓存又填充class缓存的。
这里还有一个很容易被忽视的重要问题,即打开查询缓存以后,即使是list方法也可能遇到1+N的问题!相同条件第一次list的时候,因为查询缓存中找不到,不管class缓存是否存在数据,总是发送一条sql语句到数据库获取全部数据,然后填充查询缓存和 class缓存。但是第二次执行的时候,问题就来了,如果你的class缓存的超时时间比较短,现在class缓存都超时了,但是查询缓存还在,那么 list方法在获取id串以后,将会一个一个去数据库load!因此,class缓存的超时时间一定不能短于查询缓存设置的超时时间!如果还设置了发呆时间的话,保证class缓存的发呆时间也大于查询的缓存的生存时间。这里还有其他情况,比如class缓存被程序强制evict了,这种情况就请自己注意了。
另外,如果hql查询包含select字句,那么查询缓存里面的value就是整个结果集了。
当hibernate更新数据库的时候,它怎么知道更新哪些查询缓存呢?
hibernate在一个地方维护每个表的最后更新时间,其实也就是放在上面net.sf.hibernate.cache.UpdateTimestampsCache所指定的缓存配置里面。
当通过hibernate更新的时候,hibernate会知道这次更新影响了哪些表。然后它更新这些表的最后更新时间。每个缓存都有一个生成时间和这个缓存所查询的表,当hibernate查询一个缓存是否存在的时候,如果缓存存在,它还要取出缓存的生成时间和这个缓存所查询的表,然后去查找这些表的最后更新时间,如果有一个表在生成时间后更新过了,那么这个缓存是无效的。
可以看出,只要更新过一个表,那么凡是涉及到这个表的查询缓存就失效了,因此查询缓存的命中率可能会比较低。
Collection缓存
需要在hbm的collection里面设置
<cache usage="read-write"/>
假如class是Cat,collection叫children,那么ehcache里面配置
<cache name="com.xxx.pojo.Cat.children"
maxElementsInMemory="20" eternal="false" timeToIdleSeconds="3600" timeToLiveSeconds="7200"
overflowToDisk="true" />
Collection的缓存和前面查询缓存的list一样,也是只保持一串id,但它不会因为这个表更新过就失效,一个collection缓存仅在这个collection里面的元素有增删时才失效。
这样有一个问题,如果你的collection是根据某个字段排序的,当其中一个元素更新了该字段时,导致顺序改变时,collection缓存里面的顺序没有做更新。
缓存策略
只读缓存(read-only):没有什么好说的
读/写缓存(read-write):程序可能要的更新数据
不严格的读/写缓存(nonstrict-read-write):需要更新数据,但是两个事务更新同一条记录的可能性很小,性能比读写缓存好
事务缓存(transactional):缓存支持事务,发生异常的时候,缓存也能够回滚,只支持jta环境,这个我没有怎么研究过
读写缓存和不严格读写缓存在实现上的区别在于,读写缓存更新缓存的时候会把缓存里面的数据换成一个锁,其他事务如果去取相应的缓存数据,发现被锁住了,然后就直接取数据库查询。
在hibernate2.1的ehcache实现中,如果锁住部分缓存的事务发生了异常,那么缓存会一直被锁住,直到60秒后超时。
不严格读写缓存不锁定缓存中的数据。
使用二级缓存的前置条件
你的hibernate程序对数据库有独占的写访问权,其他的进程更新了数据库,hibernate是不可能知道的。你操作数据库必需直接通过 hibernate,如果你调用存储过程,或者自己使用jdbc更新数据库,hibernate也是不知道的。hibernate3.0的大批量更新和删除是不更新二级缓存的,但是据说3.1已经解决了这个问题。
这个限制相当的棘手,有时候hibernate做批量更新、删除很慢,但是你却不能自己写jdbc来优化,很郁闷吧。
SessionFactory也提供了移除缓存的方法,你一定要自己写一些JDBC的话,可以调用这些方法移除缓存,这些方法是:
void evict(Class persistentClass)
Evict all entries from the second-level cache.
void evict(Class persistentClass, Serializable id)
Evict an entry from the second-level cache.
void evictCollection(String roleName)
Evict all entries from the second-level cache.
void evictCollection(String roleName, Serializable id)
Evict an entry from the second-level cache.
void evictQueries()
Evict any query result sets cached in the default query cache region.
void evictQueries(String cacheRegion)
Evict any query result sets cached in the named query cache region.
不过我不建议这样做,因为这样很难维护。比如你现在用JDBC批量更新了某个表,有3个查询缓存会用到这个表,用evictQueries (String cacheRegion)移除了3个查询缓存,然后用evict(Class persistentClass)移除了class缓存,看上去好像完整了。不过哪天你添加了一个相关查询缓存,可能会忘记更新这里的移除代码。如果你的 jdbc代码到处都是,在你添加一个查询缓存的时候,还知道其他什么地方也要做相应的改动吗?
以上部分为转载
//////=======================================================
以下为翻译
hibernate 缓存
Cache mappings
类或者集合映射的<CACHE>元素为下面的格式:
<cache
usage="transactional|read-write|nonstrict-read-write|read-only" (1)
region="RegionName" (2)
include="all|non-lazy" (3)
/>
(1) usage (必须) 详细指明缓存的策略:事务级,读-写,非严格读写,只读。
(2) region (可选,默认为类名或者为集合的角色名称) 详细说明两级缓存区域的名称
(3) include (可选,默认为all) non-lazy详细指明在属性级的延迟加载使用使用fetch激活时,使用lazy="true"的实体映射属性可能不会被缓存
19.2.2. Strategy: read only
如果你的应用中只需要读,而从不修改持久类的实例,只读级策略的缓存可能被使用,这是最简单性能最好的策略,在集群中使用是十分安全的(前提是数据不会被修改)。
<class name="eg.Immutable" mutable="false">
<cache usage="read-only"/>
....
</class>
19.2.3. Strategy: read/write
如果你的应用需要更新数据,读写缓存可能比较合适,当要求序列化隔离事务级时,这种缓存策略不应该使用,如果缓存是在JTA环境下,你必须指明
hibernate.transaction.manager_lookup_class属性的值,命名包含在JTA 事务管理下的策略,在其它的环境中,你必须确保在session.close()或者调用session.disconnect()前
,事务全部完成。如果使用这种策略在集群中,必须确保底层的缓存实现支持锁,内嵌提供的缓存不支持。
<class name="eg.Cat" .... >
<cache usage="read-write"/>
....
<set name="kittens" ... >
<cache usage="read-write"/>
....
</set>
</class>
19.2.4. Strategy: nonstrict read/write
如果应用只是偶尔需要更新数据(例如,几乎不可能两个事务会试图同一时间修改同一条记录),不需要严格的事务隔离,非严格读写缓存是合适的,如果在JTA环境中使用缓存,
需要详细指明hibernate.transaction.manager_lookup_class,在其它的环境中,应该确保有事务在session.close()或者Session.disconnect()被调用前完成。
19.2.5. Strategy: transactional
事务级缓存策略支持像JBOSS TreeCache这样的事务级缓存提供者,如果在JTA环境中必须指明hibernate.transaction.manager_lookup_class.
19.3. Managing the caches
无论你传递一个对象去save(),update() 或者saveOrUpdate(),还是你使用load(),get(),list(),iterate()or scroll(),重新取回一个对象,这个对象都会被添加到session的缓存
中。当随后调用flush()时,对象的状态会与数据库同步,如果你不想让这个同步发生,或者你正在处理一个巨大数量的对象,需要有效管理内存,使用evict()从session缓存中移
除这些对象和它们的集合。
ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
while ( cats.next() ) {
Cat cat = (Cat) cats.get(0);
doSomethingWithACat(cat);
sess.evict(cat);
}
Session也提供了一个contains()方法去确认一个对象是否属于这个session缓存。
调用Session.clear()可以从session 缓存中完全驱逐所有的对象。
为二级缓存,SessionFactory有驱逐处于缓存状态的实例,整个类,集合实例,或者整个集合角色的方法
sessionFactory.evict(Cat.class, catId); //evict a particular Cat
sessionFactory.evict(Cat.class); //evict all Cats
sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections
The CacheMode controls how a particular session interacts with the second-level cache.
CacheMode.NORMAL - read items from and write items to the second-level cache
CacheMode.GET - read items from the second-level cache, but don't write to the second-level cache except when updating data
CacheMode.PUT - write items to the second-level cache, but don't read from the second-level cache
CacheMode.REFRESH - write items to the second-level cache, but don't read from the second-level cache, bypass the effect of hibernate.cache.use_minimal_puts,
forcing a refresh of the second-level cache for all items read from the database
To browse the contents of a second-level or query cache region, use the Statistics API:
Map cacheEntries = sessionFactory.getStatistics()
.getSecondLevelCacheStatistics(regionName)
.getEntries();
You'll need to enable statistics, and, optionally, force Hibernate to keep the cache entries in a more human-understandable format:
hibernate.generate_statistics true
hibernate.cache.use_structured_entries true
19.4. The Query Cache
查询结果集也可以被缓存,这仅仅对频繁运行使用相同参数的查询有用,必须首先激活查询缓存,才能使用查询缓存。
hibernate.cache.use_query_cache true
这个设置引发两个新的缓存区域的创建,一个控制缓存查询结果集,另一个控制最新修改查询表的时间戳。注意,查询缓存不会缓存在结果集中实际实体的状态;它仅仅缓存标识
值和结果值的类型,因此查询缓存常常与二级缓存联合使用。
大部分的查询操作不会从缓存中受益,默认查询不会被缓存,为了使缓存可用,调用Query.setCacheable(true).这个调用允许查询执行时寻找已经缓存的结果,或者添加结果到缓
存中。
如果你需要一个精细地控制查询缓存的方案,通过调用Query.setCacheRegion(),你可以为具体的查询指明缓存区域的名称.
List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
.setEntity("blogger", blogger)
.setMaxResults(15)
.setCacheable(true)
.setCacheRegion("frontpages")
.list();
如果查询想要刷新它查询的缓存区域,应该调用Query.setCacheMode(CacheMode.REFRESH)。当底层数据可能被单独的程序修改时,这是非常有用的。同时允许选择性地刷新具体的
查询结果集。有一个更有效率地清空查询缓存区域的作是通过sessionFactory.evictQueries()
//以下为实例部分
spring集成hibernate
1、管理SessionFactory
spring中对应的Bean类为org.springframework.orm.hibernate3.LocalSessionFactoryBean
配置文件:
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver" />
<property name="url" value="jdbc:oralce:thin:@10.8.2.11:1521:hollycrm" />
<property name="username" value="system" />
<property name="password" value="system" />
<property name="maxActive" value="50" />
<property name="maxIdle" value="10" />
<property name="minIdle" value="5" />
<property name="maxWait" value="20000" />
<property name="removeAbandonedTimeout" value="120" />
<property name="removeAbandoned" value="true" />
</bean>
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource" /><!-- 数据源 -->
<!--
-->
<property name="mappingResources">
<list>
<value>***.hbm.xml</value>
<value>.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect" >org.springframework.dialect.OracleDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd"> <beans> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" scope="singleton" > <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop> <prop key="hibernate.cache.use_query_cache">true</prop> </props> </property> <property name="mappingResources"> <list> <value>com/project/dir/model/dir.hbm.xml</value> </list> </property> <property name="dataSource" ref="myDataSource"></property> </bean> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" scope="prototype"> <property name="sessionFactory" ref="sessionFactory"></property> </bean> <bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="url" value="jdbc:oracle:thin:@10.8.2.11:1521:hollycrm"></property> <property name="username" value="bjunicom3"></property> <property name="password" value="bjunicom3" /> <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property> <property name="maxActive" value="10" /> <property name="maxIdle" value="5" /> <property name="minIdle" value="2" /> <property name="maxWait" value="20000" /> <property name="removeAbandonedTimeout" value="120" /> <property name="removeAbandoned" value="true" /> </bean> <bean id="dirDao" class="com.project.dir.dao.DirDAO"> <property name="sessionFactory" ref="sessionFactory"></property> <property name="transactionManager" ref="transactionManager"></property> </bean> </beans>
package com.project.dir.dao; import org.springframework.orm.hibernate3.support.HibernateDaoSupport; import org.springframework.orm.hibernate3.HibernateTransactionManager; import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.orm.hibernate3.HibernateTemplate; import org.springframework.orm.hibernate3.HibernateCallback; import org.hibernate.Session; public class DirDAO extends HibernateDaoSupport { HibernateTransactionManager transactionManager; public void setTransactionManager(HibernateTransactionManager transactionManager){ this.transactionManager = transactionManager; } public Object list(){ TransactionTemplate tt = new TransactionTemplate(transactionManager); return tt.execute(new TransactionCallback(){ public Object doInTransaction(TransactionStatus ts){ return getHibernateTemplate().execute(new HibernateCallback(){ public Object doInHibernate(Session session){ java.util.List l = new java.util.ArrayList(); l = session.createQuery("from Dir").list(); // int i=0; // for(java.util.Iterator it = l.iterator();it.hasNext();){ // System.out.print(it.next()); // if(i++>40) // break; // } return l; } }); } }); } public void list2(){ TransactionTemplate tt = new TransactionTemplate(transactionManager); tt.execute(new TransactionCallbackWithoutResult(){ public void doInTransactionWithoutResult(TransactionStatus ts){ getHibernateTemplate().execute(new HibernateCallback(){ public java.util.List doInHibernate(Session session){ java.util.List l = new java.util.ArrayList(); java.util.Iterator it = session.createQuery("from Dir").iterate(); int i=0; for(;it.hasNext();){ System.out.println(it.next()); if(i++>40) break; } return l; } }); } }); } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.project.dir.model.Dir" table="tbl_infor_dir" > <cache usage="read-write"/> <id name="id" type="java.lang.String" column="dir_id"> <generator class="uuid.hex" /> </id> <property name="name" column="dir_name" type="java.lang.String" not-null="true" length="45" /> <property name="parentId" column="super_dir_id" type="java.lang.String" length="45" /> </class> </hibernate-mapping>
ehcache.xml
<?xml version="1.0" encoding="UTF-8"?> <ehcache> <diskStore path="java.io.tmpdir"/> <defaultCache maxElementsInMemory="10000" eternal="false" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" diskSpoolBufferSizeMB="30" maxElementsOnDisk="10000000" diskPersistent="false" diskExpiryThreadIntervalSeconds="120" memoryStoreEvictionPolicy="LRU" /> </ehcache>
发表评论
-
solr/home 设置
2013-04-21 00:44 1247solr/home是solr实例化core核的依据和入口,是必 ... -
CronTrigger Tutorial
2011-02-24 18:58 914转载地址:http://www.quartz-schedule ... -
事务未正确关闭引起的HIBERNATE SESSION不能正确关闭
2010-10-30 13:46 1666问题现象: 第一 ... -
hibernate 四种抓取策略
2010-10-24 10:42 924转载:http://www.cnblogs.com ... -
cas分析
2010-05-10 13:20 1973Central Authentication Service ... -
FCKeditor2.6.5及后续版本 for PHP配置及中文上传乱码解决!
2009-12-10 13:37 1407对于Fckeditor上传中文名文件时显示乱码的问题,现公布方 ... -
xpath语法
2009-10-12 21:02 928转载:http://www.w3schools.com/XPa ... -
jstl标签中循环map
2009-10-12 20:58 2587<% Map map = new HashMap(); ... -
log4j输出多个自定义日志文件(分离日志)
2009-06-24 11:30 2600转载: http://wangjc-opal.iteye.co ... -
错误: 必须限制口令文件读取访问
2008-10-10 17:06 3090转载:http://hi.baidu.com/lifecodi ... -
spring AOP使用结总结
2008-09-12 14:23 1107AOP使用结总结 最近需要 ... -
log4j手动加载配置文件
2008-09-10 15:26 3174PropertyConfigurator.configur ... -
lucene应用入门1
2008-07-06 16:49 2150简单的建立索引和索引 ... -
多对多查询的条件设置和删除问题
2008-07-03 14:50 1501select 父 from 父类 父 left join 父. ... -
DOM4J学习笔记
2008-07-01 15:07 3715DOM4J简单介绍 基本使用 读取XML文档 Import o ... -
延迟初始化错误(转载)
2008-06-12 17:52 1009转载地址:http://lz726.ite ... -
UUID [转帖]
2008-05-20 15:25 921/***********本人原创,欢迎转载,转载请保留本人信息 ... -
一段简单的发送邮件代码
2008-04-28 15:57 1042package send; import java. ... -
重新学习 Hibernate fetch lazy cascade inverse[转载]
2008-04-21 11:55 1235转载:http://www.blogjava.ne ... -
HIBERNATE2 CLOB字段延迟加载办法[转载]
2008-04-18 13:49 3087[转载]http://callan.iteye.com/blo ...
相关推荐
3. **配置DAO(Data Access Object)**:创建Hibernate DAO类,通过SessionFactory实例化Session,并在Spring中声明这些DAO为Bean。 4. **使用注解或XML映射实体**:在实体类上使用Hibernate的注解(如@Entity、@...
SSH(Struts+Spring+Hibernate)是Java Web开发中一种常见的技术栈,它将MVC设计模式、依赖注入和持久层框架集成为一个整体,大大提高了开发效率和代码的可维护性。下面我们将深入探讨SSH框架的各个组成部分及其结合...
在Spring和Hibernate集成的开发环境中,使用EhCache作为缓存机制是常见的优化策略,它能够显著提升应用程序的性能和响应速度。EhCache是一款开源的、高性能的、内存级的分布式缓存解决方案,适用于Java应用程序。...
【Spring3 Hibernate4 Ehcache整合实例详解】 在Java企业级应用开发中,Spring、Hibernate和Ehcache是三个非常重要的框架和技术。Spring作为轻量级的IoC(Inversion of Control)和AOP(Aspect Oriented ...
SSH(Spring、Struts、Hibernate)或WSH(Webwork、Spring、Hibernate)集成是Java企业级应用开发的常见实践,旨在构建高效、模块化且易于维护的系统。 首先,Webwork是Action-based的MVC框架,它的核心在于Action...
这篇关于"Spring和Hibernate集成Demo"的内容将深入探讨这两者如何协同工作,以及如何构建一个集成的小型项目。 **Spring框架** Spring的核心是依赖注入(Dependency Injection,DI),它允许开发者通过配置文件或...
通过扩展这个例子,你可以学习更多关于Spring Boot的特性,如安全控制、国际化支持、邮件服务等,以及Hibernate的高级特性,如懒加载、缓存管理等。同时,Thymeleaf也能帮助你更好地理解服务器端模板引擎的使用,...
标题 "gwt+spring+hibernate" 涉及的是一个使用Google Web Toolkit (GWT)、Spring框架和Hibernate ORM技术的集成示例。这是一个常见的Web应用开发组合,用于构建高效、可扩展且功能丰富的Java web应用程序。下面将...
《Hibernate与Spring集成详解》 在Java开发领域,Spring框架以其强大的依赖注入和面向切面编程能力,成为了企业级应用的首选。而Hibernate作为一款优秀的对象关系映射(ORM)工具,极大地简化了数据库操作。当这...
在IT行业中,Spring、Spring MVC和Hibernate是三个非常重要的开源框架,它们分别在不同层面上为Java应用提供了强有力的支持。本篇文章将详细讲解这三个框架的基本概念、整合过程以及为何适合初学者。 首先,Spring...
下面我们将详细探讨Spring如何与Hibernate进行集成,并通过实例来理解这个过程。 1. **Spring对Hibernate的支持** Spring提供了对Hibernate的全面支持,包括SessionFactory的创建、事务管理、DAO(数据访问对象)...
在使用 Spring 和 Hibernate 进行项目开发时,MyEclipse 是一个常用的集成开发环境(IDE)。MyEclipse 提供了对 Spring 和 Hibernate 的良好支持,包括自动配置、代码生成、调试等功能,使得开发者可以快速构建基于...
通过这个"Spring4+Hibernate4二级缓存实例源码",你可以学习到如何在实际项目中结合Spring和Hibernate实现二级缓存,提高应用的运行效率。同时,深入理解缓存的工作原理和最佳实践,对于优化系统的性能和架构有着...
在Java Web开发中,Spring和Hibernate是两个非常重要的框架,它们分别处理应用程序的依赖管理和持久化数据。Spring是一个全面的后端开发框架,提供了一系列强大的功能,如IoC(Inversion of Control)容器、AOP...
Spring、Hibernate和Struts是Java Web开发中的三大框架,它们的集成使用能够构建高效、灵活且可维护的Web应用程序。本实例代码提供了在MyEclipse环境下整合这三大框架的实践指导。 Spring框架作为核心,主要负责...
在这个例子中,我们将探讨如何将XFire、Spring和Hibernate这三个强大的工具集成为一个整体,以实现高效的Web服务和持久化管理。 首先,XFire是一款轻量级的Java Web服务框架,它允许开发者快速地创建和部署SOAP服务...
在Spring项目中集成Hibernate,我们需要: 1. **引入Hibernate依赖**:在pom.xml中添加Hibernate的相关依赖,包括hibernate-core、hibernate-entitymanager等。 2. **配置Hibernate**:在Spring的配置文件中,我们...
结合 Spring 和 Hibernate 进行开发,通常会使用 Spring 的 DAO(Data Access Object)模板或者 JPA 的 Repository 抽象来封装数据库访问逻辑。Spring 的事务管理可以覆盖 Hibernate 的事务,实现统一的事务策略。...
例如,选择合适的Struts2拦截器来提高性能,使用Spring的AOP进行日志记录,或者利用Hibernate的二级缓存提升数据库操作速度。此外,安全方面也不容忽视,如防止SQL注入、XSS攻击等。 总的来说,"Struts2_Spring_...
在IT行业中,Spring、Hibernate和Flex是三种非常重要的技术,分别用于不同的领域。Spring是一个全面的Java企业级应用开发框架,Hibernate是一个强大的对象关系映射(ORM)框架,而Flex则是一种用于创建富互联网应用...