使用二级缓存的前置条件
你的hibernate程序对数据库有独占的写访问权,其他的进程更新了数据库,hibernate是不可能知道的。你操作数据库必需直接通过hibernate,如果你调用存储过程,或者自己使用jdbc更新数据库,hibernate也是不知道的。hibernate3.0的大批量更新和删除是不更新二级缓存的,但是据说3.1已经解决了这个问题。
这个限制相当的棘手,有时候hibernate做批量更新、删除很慢,但是你却不能自己写jdbc来优化,很郁闷吧。
SessionFactory也提供了移除缓存的方法,你一定要自己写一些JDBC的话,可以调用这些方法移除缓存,这些方法是:
void evict(Class persistentClass)
void evict(Class persistentClass, Serializableid)
void evictCollection(String roleName)
void evictCollection(String roleName, Serializableid)
void evictQueries()
void evictQueries(String cacheRegion)
不过我不建议这样做,因为这样很难维护。比如你现在用JDBC批量更新了某个表,有3个查询缓存会用到这个表,用evictQueries(StringcacheRegion)移除了3个查询缓存,然后用evict(ClasspersistentClass)移除了class缓存,看上去好像完整了。不过哪天你添加了一个相关查询缓存,可能会忘记更新这里的移除代码。如果你的jdbc代码到处都是,在你添加一个查询缓存的时候,还知道其他什么地方也要做相应的改动吗?
<!-- 开启二级缓存 默认开启 -->
<propertyname="cache.use_second_level_cache">true</property>
<!-- 指定二级缓存的拥有者 -->
<propertyname="cache.provider_class">
net.sf.ehcache.hibernate.EhCacheProvider
</property>
<!-- 指定二级缓存的实体类 可在实体配置文件中进行配置
<class-cache usage="read-only"class="com.lovesmile.oa.entity.User"/>
-->
<propertyname="cache.use_query_cache">true</property>
<propertyname="generate_statistics">true</property>
2.在Web项目src目录下添加ehcache.xml,它包含如下内容:
ehcache.xml
3.第一种:在实体xml映射中添加(位置如下:)
3.第二种:注解方式:或者在实体类添加(位置:在类上添加)
@Entity
@Table(name = "DEPARTMENTS", schema = "LOVESMILE")
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class Department implements java.io.Serializable{...
注意点:
1.使用hql查询语句时:hql将作为key值存在二级缓存集合中,如果缓存存在相同key,将不进行数据库查询。
2.创建query,调用query.setCacheable(true)--->(开启二级缓存,默认为关闭的);进行缓存,每个需要用到二级缓存的query都要调用。
3....
----------------------------------------------------
总结:
不要想当然的以为缓存一定能提高性能,仅仅在你能够驾驭它并且条件合适的情况下才是这样的。hibernate的二级缓存限制还是比较多的,不方便用jdbc可能会大大的降低更新性能。在不了解原理的情况下乱用,可能会有1+N的问题。不当的使用还可能导致读出脏数据。
如果受不了hibernate的诸多限制,那么还是自己在应用程序的层面上做缓存吧。
在越高的层面上做缓存,效果就会越好。就好像尽管磁盘有缓存,数据库还是要实现自己的缓存,尽管数据库有缓存,咱们的应用程序还是要做缓存。因为底层的缓存它并不知道高层要用这些数据干什么,只能做的比较通用,而高层可以有针对性的实现缓存,所以在更高的级别上做缓存,效果也要好些吧。
然后就是自己测试了 ...