此文的目的只是想把HIBERNATE缓存和应用的业务缓存集中管理,并不提倡过多干预HIBERNATE的二级缓存,只是希望能在某个特殊的时候能派上用场,当然你也可以从此文了解到HIBERNATE二级缓存的一点细节。本文不讲如何通过Hibernater提供的标准接口来操作缓存,而是直接操作底层的缓存。
由于各种原因,系统缓存可能会出现脏数据,这时你可能不想重启服务器,又能把所有缓存清掉。
一年前,当我发现不时的有新手在项目里面使用了JDBC更新了数年据库,但没有更新HIBERNATE二级缓存,缓存的失效时间配了一天,结果某天出现脏数据后,服务器在用,不能因为这个错误而暂停几千个客户的服务,结果这一天问题就不断的出现,那个郁闷得真不行...,于是就着手把HIBERNATE的缓存也纳进来统一管理。
好,不说费话了,管理二级缓存,要先从HIBERNATE的缓存配置着手,我使用Spring来管理数据源和SessionFactory,下面是SessionFactory Bean的一个属性
<property name="hibernateProperties">
<props>
<!-- 缓存操作提供者实现类,此类只要实现了org.hibernate.cache.CacheProvider就行 -->
<prop key="hibernate.cache.provider_class">
com.esc.cache.OscacheProvider
</prop>
.............
上面的这个com.esc.cache.OscacheProvider类是从com.opensymphony.oscache.hibernate.OSCacheProvider复制过来的,只是改了一两个地方,这个类记录应用启动时,Hibernate初始化二级缓存的过程,下面分析一下源码
package com.esc.cache;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.hibernate.cache.Cache;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.CacheProvider;
import org.hibernate.cache.Timestamper;
import org.hibernate.util.StringHelper;
import com.esc.common.util.SysContext;
import com.opensymphony.oscache.base.CacheEntry;
import com.opensymphony.oscache.base.Config;
import com.opensymphony.oscache.general.GeneralCacheAdministrator;
import com.opensymphony.oscache.util.StringUtil;
public class OscacheProvider implements CacheProvider {
public static final Logger LOG = SysContext.getLogger();
// 这个属性就是在SPRING配置文件中指定缓存配置文件路径的属性名
public static final String OSCACHE_CONFIGURATION_RESOURCE_NAME = "com.opensymphony.oscache.configurationResourceName";
/** The <tt>OSCache</tt> refresh period property suffix. */
public static final String OSCACHE_REFRESH_PERIOD = "refresh.period";
/** The <tt>OSCache</tt> CRON expression property suffix. */
public static final String OSCACHE_CRON = "cron";
// 缓存的操作最终通过此实例进行,
private static GeneralCacheAdministrator cache;
// 应用启动时,首先执行此方法
public void start(Properties hibernateSystemProperties)
throws CacheException {
if (cache == null) {
// construct the cache
LOG.debug("Starting OSCacheProvider...");
// 取得配置文件
String configResourceName = null;
if (hibernateSystemProperties != null) {
configResourceName = (String) hibernateSystemProperties
.get(OSCACHE_CONFIGURATION_RESOURCE_NAME);
}
if (StringUtil.isEmpty(configResourceName)) {
// 如果配置文件没有内容,则使用默认的配置初始化底层缓存实例
cache = new GeneralCacheAdministrator();
} else {//否则就使用用户指定的配置初始化缓存实例
Properties propertiesOSCache = Config.loadProperties(
configResourceName, this.getClass().getName());
cache = new GeneralCacheAdministrator(propertiesOSCache);
}
LOG.debug("OSCacheProvider started.");
} else {
LOG.warn("Tried to restart OSCacheProvider, which is already running.");
}
}
/*执行完start方法后,Hibernate会为每一个配置了二级缓存的实体调用一次本方法,以创建一个它自已缓存操作实例,
此实例实现了org.hibernate.cache.Cache接口,每个实例最终都通过操作全局静态变量cache来读写缓存*/
public Cache buildCache(String region, Properties properties)
throws CacheException {
if (cache != null) {
LOG.debug("building cache in OSCacheProvider...");
String refreshPeriodString = cache.getProperty(StringHelper
.qualify(region, OSCACHE_REFRESH_PERIOD));
int refreshPeriod = refreshPeriodString == null ? CacheEntry.INDEFINITE_EXPIRY
: Integer.parseInt(refreshPeriodString.trim());
String cron = cache.getProperty(StringHelper.qualify(region,
OSCACHE_CRON));
// 此处被修改,OscacheImp类是我自已实现org.hibernate.cache.Cache接口缓存存取类
return new OscacheImp(cache, refreshPeriod, cron, region);
}
throw new CacheException(
"OSCache was stopped or wasn't configured via method start.");
}
/**
* 这是应用正常停止时被调用的方法
*/
public void stop() {
if (cache != null) {
LOG.debug("Stopping OSCacheProvider...");
cache.destroy();
cache = null;
LOG.debug("OSCacheProvider stopped.");
}
}
/**
* 这个方法是我另外加进去的,就是用于取得底层缓存实例,
*/
public static GeneralCacheAdministrator getCache() {
return cache;
}
//下面的两个方法没细看,我就不忽悠了
/**
* @see org.hibernate.cache.CacheProvider#nextTimestamp()
*/
public long nextTimestamp() {
return Timestamper.next();
}
/**
* This method isn't documented in Hibernate:
*
* @see org.hibernate.cache.CacheProvider#isMinimalPutsEnabledByDefault()
*/
public boolean isMinimalPutsEnabledByDefault() {
return false;
}
}
上面我将buildCache方法的返回值改成我自的实现,下面就是这个实现类,这个实现也是从oscache那COPY的,只是加上了一点自已的代码,还改良了一个地方。
package com.esc.cache;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.cache.Cache;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.Timestamper;
import com.opensymphony.oscache.base.CacheEntry;
import com.opensymphony.oscache.base.EntryRefreshPolicy;
import com.opensymphony.oscache.base.NeedsRefreshException;
import com.opensymphony.oscache.general.GeneralCacheAdministrator;
import com.esc.common.util.SysContext;
public class OscacheImp implements CacheInterFace,Cache{
/*上文的那个全局静态变量通过构造函数传到这里,本类所有操作都是操作这个属性完成*/
private static GeneralCacheAdministrator cache;
private final int refreshPeriod;
private final String cron;
private final String regionName;
private final String[] regionGroups;
public OscacheImp() {
this(OscacheProvider.getCache(), -1, null, "custumerRegion");
}
public OscacheImp(GeneralCacheAdministrator cache, int refreshPeriod,String cron, String region) {
if(OscacheImp.cache==null){
OscacheImp.cache = cache;
}
this.refreshPeriod = refreshPeriod;
this.cron = cron;
this.regionName = region;
this.regionGroups = new String[] {region};
}
//放入缓存
public void put(Object key, Object value) throws CacheException {
String stringKey = toString(key);
cache.putInCache( stringKey, value, regionGroups );
//我加的,我把HIBERNATE所有缓存的KEY放入了应用的一个LinkedHasMap中,这就是我能从底层干预其缓存的基本条件之一,另一个条件就是我也拿到上文一再提到的全局静态变量cache
List<Object> cacheKeys = SysContext.getCacheKeys();
if (!cacheKeys.contains(stringKey))
cacheKeys.add(stringKey);
}
//从缓存取
public Object get(Object key) throws CacheException {
try {
Object obj = cache.getFromCache( toString(key), refreshPeriod, cron );
if (obj == null) {
SysContext.getCacheKeys().remove(key);
}
return obj;
}
catch (NeedsRefreshException e) {
cache.cancelUpdate( toString(key) );
return null;
}
}
//从缓存移除
public void remove(Object key) throws CacheException {
String stringKey = toString(key);
cache.flushEntry( stringKey );
SysContext.getCacheKeys().remove(key);
}
//这就是上文我说的改良的地方了,原来String+String,哈哈,忽悠了一把
private String toString(Object key) {
return new StringBuilder(String.valueOf(key)).append(".").append(regionName).toString();
}
}
上面已经把底层的cache实例拿到,hibernate放入缓存的KEY也全部拿到,想怎么做就由你了,不过有一点,我那时找了很久,就是没有找到取oscache所有缓存KEY的方法,所以才这样自已弄了一份,如果有高手知道方法,分享一下吧。
分享到:
相关推荐
- **外置缓存**:又称为Hibernate的二级缓存,是一个可配置的插件,默认情况下不会启用。二级缓存中的数据是数据库数据的副本,存储介质可以是内存或硬盘。 - **应用场景**:适用于跨`Session`的数据共享,可以...
在Hibernate中,缓存管理是持久化层优化的关键组成部分,它提供了两种级别的缓存:一级缓存和二级缓存。 1. **缓存简介** - 缓存通常位于内存中,以提高数据读取速度,但根据需要,也可能使用硬盘作为辅助存储。 ...
本文将深入探讨 Hibernate 的缓存机制,包括其两个级别——一级缓存和二级缓存,并讨论它们的工作原理、范围、并发访问策略以及如何管理和配置。 1. **一级缓存** - **范围与作用**:一级缓存是 Session 级别的...
Hibernate支持多级缓存管理机制,包括一级缓存和二级缓存。 #### 二、缓存范围 缓存范围定义了缓存的生命周期以及哪些组件能够访问它。根据不同的应用场景,Hibernate支持三种缓存范围: 1. **事务范围缓存**:...
根据不同的应用场景,Hibernate提供了不同级别的缓存支持,包括一级缓存(Session级别的缓存)和二级缓存(SessionFactory级别的缓存)。这两种缓存机制各有侧重,下面将详细介绍。 #### 三、一级缓存:Session级别...
Hibernate中使用了一级缓存和二级缓存的机制来提高程序的性能. 一 为什么要使用缓存? 缓存是一块存储区域,可能是一块内存,也可能是一块硬盘.缓存能起到缓冲的作用,把程序经常使用...
##### 2.2 Hibernate二级缓存配置 **二级缓存**是在SessionFactory级别配置的,它可以跨Session共享数据,提高查询效率。配置二级缓存需要以下几个步骤: 1. **选择缓存实现**:Hibernate支持多种缓存实现方式,如...
通过合理配置和利用 Hibernate 的一级缓存和二级缓存,开发者可以在不影响应用程序逻辑的同时显著提高系统的整体性能。此外,对于大型项目来说,合理的缓存策略还能帮助节省宝贵的资源,提高用户体验。
- **二级缓存**:SessionFactory级别,进程或集群范围,可配置,存储散装数据,依赖于并发访问策略。 - **查询缓存**:基于二级缓存,缓存查询结果,提高查询速度。 在使用Hibernate缓存时,开发者应根据业务需求...
Hibernate提供了First-Level Cache(一级缓存)和Second-Level Cache(二级缓存)来优化性能。一级缓存是每个Session的私有缓存,存储了Session内的实体对象,避免了频繁的数据库访问。二级缓存是SessionFactory级别...
一级缓存和二级缓存的使用显著提高了 Hibernate 的性能,减少了对数据库的访问,从而降低了系统负载。通过合理地配置缓存策略,比如选择适当的并发访问策略和数据过期策略,可以进一步优化系统的性能。一级缓存的...
- **二级缓存(Second-Level Cache)**:可选启用,作用于整个应用程序或集群范围内,用于跨`Session`持久化数据。启用二级缓存需要额外配置,并且要考虑并发控制问题。 ##### 事务管理 Hibernate支持多种事务管理...
Hibernate提供了一级缓存,即Session级别的缓存,但为了进一步提高性能,引入了二级缓存。二级缓存是SessionFactory级别的,可以跨Session共享数据,减少对数据库的访问。同时,查询缓存则能存储查询结果,避免重复...
Hibernate支持二级缓存,可以提高数据访问性能。一级缓存是Session级别的,每个Session都有自己的缓存;二级缓存是SessionFactory级别的,可被多个Session共享。 8. **事务处理**: Hibernate支持事务管理,通常...
Hibernate内置了一级缓存(Session级别的)和二级缓存(SessionFactory级别的)。一级缓存默认开启,二级缓存可选,用于提高性能但需合理配置以避免数据不一致。 8. **关联映射**: Hibernate支持一对一、一对多...
9. **第一级缓存和第二级缓存**:第一级缓存是会话级别的,自动管理实体对象,提高性能;第二级缓存可跨会话共享,进一步优化性能,但需要额外配置和管理。 10. **事务管理**:Hibernate支持JTA(Java Transaction ...
5. **第二级缓存**:介绍了Hibernate的缓存机制,包括SessionFactory级别的第一级缓存和可选的第二级缓存,以及查询缓存,提高数据访问效率。 6. **拦截器与事件监听**:通过实现特定接口,可以自定义拦截器或事件...
5. 二级缓存在 SessionFactory 中存放 6. SessionFactory 和数据库的链接没有直接的关系 Session 类 1. CRUD 操作由 Session 来完成的 2. 一个 Session 代表数据库的一个链接 Hibernate 的反向工程 1. 第一步 2....
Hibernate 3.3内置了第一级缓存(Session缓存)和第二级缓存。第一级缓存默认开启,用于存储会话内的对象;第二级缓存可以全局共享,可选的缓存提供商如Ehcache、Infinispan等,用于跨会话的数据缓存。 9. **关联...
9. **第二级缓存(Second-Level Cache)**:Hibernate 支持二级缓存,能提高数据访问速度,减少对数据库的直接访问。常用实现有Ehcache。 10. **懒加载(Lazy Loading)**:Hibernate 提供的一种优化策略,允许关联...