spring+hibernate整合ehcache

1.使用ehcache来提高系统的性能,现在用的非常多, 也支持分布式的缓存,在hibernate当中作为二级缓存的实现产品,可以提高查询性能。

2.在之前的struts2.12+Spring3.2+hibernate4.2集成系列的文章中已经集成了ehcache的jar包了, 在hibernate4.2当中可以找到ehcache-core-2.4.3.jar hibernate-ehcache-4.2.0.Final.jar

Hibernate 本身支持ehcahce的集成,提对他进行了集成的封装。

3. 在项目的src下面添加ehcache的配置文件ehcache.xml

Xml代码 收藏代码
  1. <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
  2. <!--
  3. Subdirectories can be specified below the property e.g. java.io.tmpdir/one
  4. -->
  5. <diskStore path="java.io.tmpdir"/>
  6. <!--
  7. Mandatory Default Cache configuration. These settings will be applied to caches
  8. created programmtically using CacheManager.add(String cacheName)
  9. -->
  10. <defaultCache
  11. maxElementsInMemory="10000"
  12. eternal="false"
  13. timeToIdleSeconds="120"
  14. timeToLiveSeconds="120"
  15. overflowToDisk="true"
  16. maxElementsOnDisk="10000000"
  17. diskPersistent="false"
  18. diskExpiryThreadIntervalSeconds="120"
  19. memoryStoreEvictionPolicy="LRU"
  20. />
  21. <cache name="org.hibernate.cache.spi.UpdateTimestampsCache"
  22. maxElementsInMemory="5000"
  23. eternal="true"
  24. overflowToDisk="true" />
  25. <cache name="org.hibernate.cache.internal.StandardQueryCache"
  26. maxElementsInMemory="10000"
  27. eternal="false"
  28. timeToLiveSeconds="120"
  29. overflowToDisk="true" />
  30. <!--
  31. java文件注解查找cache方法名的策略:如果不指定java文件注解中的region="ehcache.xml中的name的属性值",
  32. 则使用name名为com.lysoft.bean.user.User的cache(即类的全路径名称), 如果不存在与类名匹配的cache名称, 则用 defaultCache
  33. 如果User包含set集合, 则需要另行指定其cache
  34. 例如User包含citySet集合, 则也需要
  35. 添加配置到ehcache.xml中
  36. -->
  37. <cache name="copierCache" maxElementsInMemory="2000" eternal="false"
  38. timeToIdleSeconds="120" timeToLiveSeconds="120"
  39. overflowToDisk="true" />
  40. </ehcache>

4. 在spring 集成hibernate 的配置文件中,添加如下配置

Xml代码 收藏代码
  1. <!-- 开启查询缓存 -->
  2. <prop key="hibernate.cache.use_query_cache">true</prop>
  3. <!-- 开启二级缓存 -->
  4. <prop key="hibernate.cache.use_second_level_cache">true</prop>
  5. <!-- 高速缓存提供程序 -->
  6. <!-- 由于spring也使用了Ehcache, 保证双方都使用同一个缓存管理器 -->
  7. <prop key="hibernate.cache.region.factory_class">
  8. org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
  9. </prop>

5. Spring也使用ehcache, 所以也需要在spring配置文件中添加ehcache的配置

Xml代码 收藏代码
  1. <!-- cacheManager, 指定ehcache.xml的位置 -->
  2. <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
  3. <property name="configLocation">
  4. <value>classpath:ehcache.xml</value>
  5. </property>
  6. <!-- 由于hibernate也使用了Ehcache, 保证双方都使用同一个缓存管理器 -->
  7. <property name="shared" value="true"/>
  8. </bean>

由于hibernate 和spring都使用了ehcache, 可以由spring 或者hibernate 来管理ehcache,

使用spring管理ehcache的好处是可以使用依赖注入,可以在程序中注入使用,比较方便,因此采用spring管理ehcache比较好, 不过spring 和hibernate一起使用ehcache的话,会产生两个CacheManager,这样在分布式缓存中会有数据部同步的问题, 需要配置一下,spring和hibernate公用一个CacheManager。

EHCache升级到1.2之后,对原来CacheManager的实例化方式进行了一些修改。在之前的EHCache中,只会存在一个CacheManager的实例,所有使用EHCache组件的应用都共享这个实例。

而在EHCache 1.2之后,则提供了对多实例的支持。这样,在有多个功能模块同时使用EHCache的时候就要注意实例方式的选取了。

CacheManager是否为多实例取决于获得CacheManager的方法。如果使用构造方法来获得CacheManager对象的实例,那么就会获得一个新的CacheManager实例。而使用create()方法获得CacheManager实例的时候则会获得singleton的实例(如果还没有创建,它会自动地创建)。

现在,在一个应用中,默认情况下Hibernate会创建一个单独的CacheManager实例,如果在其他功能模块中也需要使用这个CahceManager实例,就需要使用EHCache所提供的singleton的CacheProvider。在Hibernate配置文件中的配置方法如下:

在配置hibernate的相关信息里面设置成单实例的CacheManager Factory

Xml代码 收藏代码
  1. <!-- 由于spring也使用了Ehcache, 保证双方都使用同一个缓存管理器 -->
  2. <prop key="hibernate.cache.region.factory_class">
  3. org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory
  4. </prop>

spring 配置ehcache里面需要添加这个属性

Xml代码 收藏代码
  1. <!-- 由于hibernate也使用了Ehcache, 保证双方都使用同一个缓存管理器 -->
  2. <property name="shared" value="true"/>

Java代码 收藏代码
  1. 我们来看一下hibernate配置里面 SingletonEhCacheRegionFactory这个类的源代码,
  2. String configurationResourceName = null;
  3. if ( properties != null ) {
  4. configurationResourceName = (String) properties.get( NET_SF_EHCACHE_CONFIGURATION_RESOURCE_NAME );
  5. }
  6. if ( configurationResourceName == null || configurationResourceName.length() == 0 ) {
  7. manager = CacheManager.create();
  8. REFERENCE_COUNT.incrementAndGet();
  9. }
  10. 我们可以看到 会以默认的配置文件名称 创建一个CacheManager 对象,并且是以CacheManager.create()方法创建的, 说明只会产生一个CacheManager 实例。
  11. 再来看一下spring EhCacheManagerFactoryBean这个类的源码
  12. private boolean shared = false;
  13. if (this.shared) {
  14. this.cacheManager = (is != null ? CacheManager.create(is) : CacheManager.create());
  15. }
  16. else {
  17. this.cacheManager = (is != null ? new CacheManager(is) : new CacheManager());
  18. }
  19. 发现里面有个share的变量, 是否是共享使用CacheManger, 如果是true, 调用的是CacheManager.create()的方法创建CacheManager,false调用 new CacheManager方法会生成多个实例。
  20. 再看看CacheManger里面的create方法源码
  21. private static volatile CacheManager singleton;
  22. if (singleton != null) {
  23. return singleton;
  24. }
  25. synchronized (CacheManager.class) {
  26. if (singleton == null) {
  27. LOG.debug("Creating new CacheManager with default config");
  28. singleton = new CacheManager();
  29. } else {
  30. LOG.debug("Attempting to create an existing singleton. Existing singleton returned.");
  31. }
  32. return singleton;
  33. }
  34. 可以看到CacheManager 定义的变量是static 的,create方面里面做了判断singleton 是否已经创建过。
  35. 配置好后, 把项目部署到tomcat上面,以debug的方式启动, 可以debug到源码可以观察CacheManger 的创建过程。
  36. 来检验一下缓存是否起作用了,添加一个User类
  37. package com.lysoft.bean.user;
  38. import java.io.Serializable;
  39. import java.util.Date;
  40. import javax.persistence.Column;
  41. import javax.persistence.Entity;
  42. import javax.persistence.GeneratedValue;
  43. import javax.persistence.Id;
  44. import javax.persistence.Table;
  45. import javax.persistence.Temporal;
  46. import javax.persistence.TemporalType;
  47. import org.hibernate.annotations.Cache;
  48. import org.hibernate.annotations.CacheConcurrencyStrategy;
  49. @Entity
  50. @Table(name = "t_user")
  51. @Cache(usage = CacheConcurrencyStrategy.READ_WRITE, region="longTimeCache")
  52. public class User implements Serializable {
  53. private static final long serialVersionUID = 4239100106344646509L;
  54. private Integer id;
  55. private String userName;
  56. private String firstName;
  57. private Date createTime;
  58. @Id @GeneratedValue
  59. public Integer getId() {
  60. return id;
  61. }
  62. public void setId(Integer id) {
  63. this.id = id;
  64. }
  65. @Column(length = 50, nullable = false)
  66. public String getUserName() {
  67. return userName;
  68. }
  69. public void setUserName(String userName) {
  70. this.userName = userName;
  71. }
  72. public String getFirstName() {
  73. return firstName;
  74. }
  75. public void setFirstName(String firstName) {
  76. this.firstName = firstName;
  77. }
  78. @Temporal(TemporalType.TIMESTAMP)
  79. public Date getCreateTime() {
  80. return createTime;
  81. }
  82. public void setCreateTime(Date createTime) {
  83. this.createTime = createTime;
  84. }
  85. }
  86. 添加了一个注解@Cache, 指定缓存策略是读和写, 并指定使用的缓存区域
  87. 在ehcache中添加一个cache配置
  88. <cache name="longTimeCache" maxElementsInMemory="2000" eternal="false"
  89. timeToIdleSeconds="300" timeToLiveSeconds="900"
  90. overflowToDisk="true" />
  91. 注意cache标签后面的 name 属性不要换行,换行了会有异常, 我上次不小心换行了, 查了半天文档都没有查到是什么问题,后来找个文件复制了一份对比才知道是换行引起的问题。
  92. 默认情况下二级缓存只会对load get 之类的方法缓存, 想list iterator 之类的方法也使用缓存 必须跟查询缓存一起使用, 在UserDaoImpl中重写listAll 方法。
  93. public List<User> listAll() {
  94. return getSession().createQuery("from User").setCacheable(true).list();
  95. }

在log4j 配置文件中 设置成debug级别

在网页中访问http://localhost:8080/SSH2/user/userList.do

第一次访问可以看到debug信息如下:

[2013-04-13 22:00:08.082] [DEBUG] [http-8080-1] [org.hibernate.cache.internal.StandardQueryCache:137] - Query results were not found in cache

[2013-04-13 22:00:08.113] [DEBUG] [http-8080-1] [org.hibernate.SQL:104] -

select

user0_.id as id1_0_,

user0_.createTime as createTi2_0_,

user0_.firstName as firstNam3_0_,

user0_.userName as userName4_0_

from

t_user user0_

缓存中找不到 Query results were not found in cache, 发出了查询sql。

第二次访问:

Debug日志

Checking query spaces are up-to-date: [t_user]

Returning cached query results

从缓存中找到了查询结果 直接返回了,没有发出查询sql。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值