使用oscahe缓存技术减少与数据库的频繁交互

此前一直不知道缓存的具体实现,只知道是把数据存储在内存中,以便下次直接从内存中读取。对于缓存的使用也没有概念,觉得缓存技术是一个比较”神秘陌生“的领域。但最近要用到缓存技术,发现还是很有必要一探究竟的。

 

缓存技术使用背景:一般来说,对于web项目,如果我们要什么数据直接jdbc查库好了,但是在遇到高并发的情形下,不可能每一次都是去查数据库,因为这样在高并发的情形下显得不太合理——频繁地与数据库交互不是件好事儿,除了在并发情况不是很多的情况下或者没有并发的情况下。我们可以找到一个解决方案:那就是第一次去查库,把查询到的数据缓存到内存中(用key来指定该数据),下次再到这一步时,判断查询条件是不是一样,一样的话,直接从内存中取;不一样则去查库,并把结果缓存起来以便下次使用……

这样做的好处,就是减少了与数据库的交互。。

 

开始使用oscahe缓存技术来探讨吧。这里我用到了oscache.jar包,反编译该jar,找到一个缓存管理的核心类GeneralCacheAdministrator.java,这个类负责创建、销毁、操作缓存Cache对象。这个类extends了一个基类AbstractCacheAdministrator,这个基类有以下一些基本属性:

 

// 缓存的内存
public static final String CACHE_MEMORY_KEY = "cache.memory";
//  缓存容量(可以容纳的key-value对数)
public static final String CACHE_CAPACITY_KEY = "cache.capacity";
//缓存的算法
  public static final String CACHE_ALGORITHM_KEY = "cache.algorithm";

 

 

看到GeneralCacheAdministrator里面有些关键的方法

 

//得到缓存
public Cache getCache()
  {
    return this.applicationCache;
  }

//从缓存中删除内容
  public void removeEntry(String key)
  {
    getCache().removeEntry(key);
  }
//从缓存中得到内容
  public Object getFromCache(String key)
    throws NeedsRefreshException
  {
    return getCache().getFromCache(key);
//取消缓存的更新
public void cancelUpdate(String key)
  {
    getCache().cancelUpdate(key);
  }
//刷新缓存
public void flushEntry(String key)
  {
    getCache().flushEntry(key);
  }
//刷新某组缓存
  public void flushGroup(String group)
  {
    getCache().flushGroup(group);
  }

……

 

还有很多方法,只不过这几个方法用得比较普遍,从代码来看也比较好理解它们的作用。 

 

一、如何在项目中使用oscahe缓存?

 

为了能够在web项目中更好地使用oscahe,首先配置是必不可少的:

进一步看GeneralCacheAdministrator.java类的构造方法:

 

 private Cache applicationCache = null;
public GeneralCacheAdministrator()
  {
    this(null);
  }

  public GeneralCacheAdministrator(Properties p)
  {
    super(p);
    log.info("Constructed GeneralCacheAdministrator()");
    createCache();
  }

 public Cache getCache()
  {
    return this.applicationCache;
  }

private void createCache()
  {
    log.info("Creating new cache");

    this.applicationCache = new Cache(isMemoryCaching(), isUnlimitedDiskCache(), isOverflowPersistence(), isBlocking(), this.algorithmClass, this.cacheCapacity);

    configureStandardListeners(this.applicationCache);
  }

 我们肯定选带参数的构造了,因为要指定一些必要的属性。。而通过createCache()方法可知,要构建一个缓存对象,可指定一些基本的属性。

 

 

<bean id="sysCacheOscache"
		class="com.opensymphony.oscache.general.GeneralCacheAdministrator"
		scope="singleton" destroy-method="destroy">
		<constructor-arg index="0">
			<props>
				<prop key="cache.memory">true</prop>
				<prop key="cache.capacity">600</prop><!-- 缓存元素个数最大值 -->
				<!-- 缓存元素超过最大值,采用先进先出(first int first out)算法移除 -->
				<prop key="cache.algorithm">com.opensymphony.oscache.base.algorithm.FIFOCache
				</prop>
			</props>
		</constructor-arg>
	</bean>

 

 

在项目中创建一个管理缓存的类ObjCacheManager,把原生的服务更好地封装:

 

public class ObjCacheManager
{
  private GeneralCacheAdministrator entityOscache;

 //这个类是用来从缓存中得到数据的
//key-缓存中的key  objLoader--数据库实体接口  params-查询参数(初始从数据库中查询所用到的参数)
  public <T> T getEntity(String key, ICacheLoader<T> objLoader, Object[] params)
    throws Exception
  {
    if ((StringUtils.IsEmpty(key)) || (objLoader== null))
    {
      return null;
    }

  //尝试从缓存中根据key取数据
    Object config = get(key);
//如果为null 从数据库中取
    if (config == null)
    {
//ICacheLoader接口里的抽象方法getEntity,待具体的类去实现
      config = objLoader.getEntity(params);
      if (config != null)
        put(key, config);//保存在缓存中
    }
    
    return config;
  }
//刷新缓存(比如数据库数据更新时,需调用此方法更新相应的缓存)
  public void flushEntry(String key)
  {
    this.entityOscache.flushEntry(key);
  }

  private Object get(String key)
  {
    try
    {
      Object obj = this.entityOscache.getFromCache(key);
      return obj;
    }
    catch (NeedsRefreshException e) {
      this.entityOscache.cancelUpdate(key);
    }
    return null;
  }

  private void put(String key, Object value)
  {
    this.entityOscache.putInCache(key, value);
  }

  public void clear()
  {
    this.entityOscache.flushAll();
  }

  public void destroy()
  {
    this.entityOscache.destroy();
  }

  public void setEntityOscache(GeneralCacheAdministrator entityOscache)
  {
    this.entityOscache = entityOscache;
  }
}

 其中,ICacheLoader是一个接口,可以定义一个抽象方法getEntity,功能是查库得到相应的缓存实体。需要的缓存的实体可以实现这个方法(具体略)。

配置该管理缓存的类:

<bean id="sysCacheManager" class="com.xxx.ObjCacheManager"
		scope="singleton" destroy-method="destroy" init-method="init">
		<property name="entityOscache">
			<ref bean="sysCacheOscache" />
		</property>
		<property name="cacheFlushFiles">
			<list>
				<!-- 这里是一些配置文件的路径-->
			</list>
		</property>
	</bean>

 这样,就可以在web项目里调用该bean来管理缓存了。。

------------------------------------------------------------

注意:

1)数据库数据更新时,别忘了调用flush缓存的方法;

2)缓存的key设置问题:

——当你需要得到一个集合时,缓存的key可用常量表示(select * from);

——当你根据不同的条件去数据库查到结果不一样时(select xxx, xx, xx… from xx where …),需要注意key不能用常量固定死,否则当你第一次查库时,会把结果缓存到内存中,而当你查询条件变化后,本来结果应该改变(重新查库。。,此时数据结构为查询结果为map,查询条件的组合为key),但是却会依旧使用第一次缓存的结果。或者你也可以用常量表示key,但key对应的value是一个map型的list,每个元素为map,每个map的key是你查询依据的条件的组合。(看你选择哪种数据结构了);

3)不要忘记数据库数据改变时,缓存也需要调用flushEntry刷新缓存中的内容,避免缓存中的内容没有及时跟数据同步。调用之后,它会重新查库,把新的结果保存在缓存中。

 

你可能感兴趣的:(Web,高并发,oscahe缓存)