`

如何干预HIBERNATE二级缓存

阅读更多
       此文的目的只是想把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的方法,所以才这样自已弄了一份,如果有高手知道方法,分享一下吧。
2
1
分享到:
评论

相关推荐

    Hibernate的缓存策略

    - **外置缓存**:又称为Hibernate的二级缓存,是一个可配置的插件,默认情况下不会启用。二级缓存中的数据是数据库数据的副本,存储介质可以是内存或硬盘。 - **应用场景**:适用于跨`Session`的数据共享,可以...

    hibernate3的缓存管理

    在Hibernate中,缓存管理是持久化层优化的关键组成部分,它提供了两种级别的缓存:一级缓存和二级缓存。 1. **缓存简介** - 缓存通常位于内存中,以提高数据读取速度,但根据需要,也可能使用硬盘作为辅助存储。 ...

    Hibernate的缓存机制

    本文将深入探讨 Hibernate 的缓存机制,包括其两个级别——一级缓存和二级缓存,并讨论它们的工作原理、范围、并发访问策略以及如何管理和配置。 1. **一级缓存** - **范围与作用**:一级缓存是 Session 级别的...

    Hibernate缓存管理

    Hibernate支持多级缓存管理机制,包括一级缓存和二级缓存。 #### 二、缓存范围 缓存范围定义了缓存的生命周期以及哪些组件能够访问它。根据不同的应用场景,Hibernate支持三种缓存范围: 1. **事务范围缓存**:...

    Hibernate的缓存应用

    根据不同的应用场景,Hibernate提供了不同级别的缓存支持,包括一级缓存(Session级别的缓存)和二级缓存(SessionFactory级别的缓存)。这两种缓存机制各有侧重,下面将详细介绍。 #### 三、一级缓存:Session级别...

    hibernate基础教程

    Hibernate中使用了一级缓存和二级缓存的机制来提高程序的性能. 一 为什么要使用缓存? 缓存是一块存储区域,可能是一块内存,也可能是一块硬盘.缓存能起到缓冲的作用,把程序经常使用...

    hibernate缓存策略

    ##### 2.2 Hibernate二级缓存配置 **二级缓存**是在SessionFactory级别配置的,它可以跨Session共享数据,提高查询效率。配置二级缓存需要以下几个步骤: 1. **选择缓存实现**:Hibernate支持多种缓存实现方式,如...

    Hibernate缓存机制探讨.doc

    通过合理配置和利用 Hibernate 的一级缓存和二级缓存,开发者可以在不影响应用程序逻辑的同时显著提高系统的整体性能。此外,对于大型项目来说,合理的缓存策略还能帮助节省宝贵的资源,提高用户体验。

    Hibernate缓存管理.doc

    - **二级缓存**:SessionFactory级别,进程或集群范围,可配置,存储散装数据,依赖于并发访问策略。 - **查询缓存**:基于二级缓存,缓存查询结果,提高查询速度。 在使用Hibernate缓存时,开发者应根据业务需求...

    Hibernate的高级操作[归纳].pdf

    Hibernate提供了First-Level Cache(一级缓存)和Second-Level Cache(二级缓存)来优化性能。一级缓存是每个Session的私有缓存,存储了Session内的实体对象,避免了频繁的数据库访问。二级缓存是SessionFactory级别...

    hibernate的缓冲介绍.doc

    一级缓存和二级缓存的使用显著提高了 Hibernate 的性能,减少了对数据库的访问,从而降低了系统负载。通过合理地配置缓存策略,比如选择适当的并发访问策略和数据过期策略,可以进一步优化系统的性能。一级缓存的...

    Hibernate的高级操作

    - **二级缓存(Second-Level Cache)**:可选启用,作用于整个应用程序或集群范围内,用于跨`Session`持久化数据。启用二级缓存需要额外配置,并且要考虑并发控制问题。 ##### 事务管理 Hibernate支持多种事务管理...

    hiber开发指南 hibernate高级特性

    Hibernate提供了一级缓存,即Session级别的缓存,但为了进一步提高性能,引入了二级缓存。二级缓存是SessionFactory级别的,可以跨Session共享数据,减少对数据库的访问。同时,查询缓存则能存储查询结果,避免重复...

    hibernate框架配置源码

    Hibernate支持二级缓存,可以提高数据访问性能。一级缓存是Session级别的,每个Session都有自己的缓存;二级缓存是SessionFactory级别的,可被多个Session共享。 8. **事务处理**: Hibernate支持事务管理,通常...

    hibernate.zip

    Hibernate内置了一级缓存(Session级别的)和二级缓存(SessionFactory级别的)。一级缓存默认开启,二级缓存可选,用于提高性能但需合理配置以避免数据不一致。 8. **关联映射**: Hibernate支持一对一、一对多...

    hibernate4 全部jar包

    9. **第一级缓存和第二级缓存**:第一级缓存是会话级别的,自动管理实体对象,提高性能;第二级缓存可跨会话共享,进一步优化性能,但需要额外配置和管理。 10. **事务管理**:Hibernate支持JTA(Java Transaction ...

    Hibernate参考文档(CHM).

    5. **第二级缓存**:介绍了Hibernate的缓存机制,包括SessionFactory级别的第一级缓存和可选的第二级缓存,以及查询缓存,提高数据访问效率。 6. **拦截器与事件监听**:通过实现特定接口,可以自定义拦截器或事件...

    Hibernate学习笔记整理

    5. 二级缓存在 SessionFactory 中存放 6. SessionFactory 和数据库的链接没有直接的关系 Session 类 1. CRUD 操作由 Session 来完成的 2. 一个 Session 代表数据库的一个链接 Hibernate 的反向工程 1. 第一步 2....

    hibernate 3.3 源码

    Hibernate 3.3内置了第一级缓存(Session缓存)和第二级缓存。第一级缓存默认开启,用于存储会话内的对象;第二级缓存可以全局共享,可选的缓存提供商如Ehcache、Infinispan等,用于跨会话的数据缓存。 9. **关联...

    hibernate-3.2源码包

    9. **第二级缓存(Second-Level Cache)**:Hibernate 支持二级缓存,能提高数据访问速度,减少对数据库的直接访问。常用实现有Ehcache。 10. **懒加载(Lazy Loading)**:Hibernate 提供的一种优化策略,允许关联...

Global site tag (gtag.js) - Google Analytics