自定义Mybatis二级缓存-上

本文探讨MyBatis框架中的二级缓存机制,解析其核心接口与默认实现,并为自定义缓存方案奠定基础。
前言

        Mybatis,是最常用的ORM框架之一。而缓存,也是我们在日常的工作中遇到的重要问题,这两者的结合实际上就落在了其自带的缓存上。
        下面,阿福带着大家去探索如何自定义Mybatis二级缓存。

二级缓存是什么?

        实际上,Mybatis共有两级缓存,其一级缓存就是针对于一次会话的,一旦会话结束了,缓存的历史使命也就结束了。当然,它是存储在本地机器的内存中的,你知道的,这势必造成了一个问题,那就是多机器缓存的共享问题,你想一想,现在谁家的应用是一台机器就能撑起来的。所以,这里就轮到我们的二级缓存出场了。
        二级缓存的一个比较明显的优势就是它是基于一个namespace的,额,你问我这是啥?我只能说,百度一下,你就知道。其还支持自定义的实现,要不然,本文的还怎么往下写!
        实际上,Mybatis为我们提供了一个接口用来进行二级缓存的扩展,这个接口就是org.apache.ibatis.cache.Cache。对,就是这个接口,我们先一起来看看这个接口吧!代码如下:

/**
 *    Copyright 2009-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.cache;

import java.util.concurrent.locks.ReadWriteLock;

/**
 * SPI for cache providers.
 * 
 * One instance of cache will be created for each namespace.
 * 
 * The cache implementation must have a constructor that receives the cache id as an String parameter.
 * 
 * MyBatis will pass the namespace as id to the constructor.
 * 
 * <pre>
 * public MyCache(final String id) {
 *  if (id == null) {
 *    throw new IllegalArgumentException("Cache instances require an ID");
 *  }
 *  this.id = id;
 *  initialize();
 * }
 * </pre>
 *
 * @author Clinton Begin
 */

public interface Cache {

  /**
   * @return The identifier of this cache
   */
  String getId();

  /**
   * @param key Can be any object but usually it is a {@link CacheKey}
   * @param value The result of a select.
   */
  void putObject(Object key, Object value);

  /**
   * @param key The key
   * @return The object stored in the cache.
   */
  Object getObject(Object key);

  /**
   * As of 3.3.0 this method is only called during a rollback 
   * for any previous value that was missing in the cache.
   * This lets any blocking cache to release the lock that 
   * may have previously put on the key.
   * A blocking cache puts a lock when a value is null 
   * and releases it when the value is back again.
   * This way other threads will wait for the value to be 
   * available instead of hitting the database.
   *
   * 
   * @param key The key
   * @return Not used
   */
  Object removeObject(Object key);

  /**
   * Clears this cache instance
   */  
  void clear();

  /**
   * Optional. This method is not called by the core.
   * 
   * @return The number of elements stored in the cache (not its capacity).
   */
  int getSize();

  /** 
   * Optional. As of 3.2.6 this method is no longer called by the core.
   *  
   * Any locking needed by the cache must be provided internally by the cache provider.
   * 
   * @return A ReadWriteLock 
   */
  ReadWriteLock getReadWriteLock();

}

        代码不是很多,主要定义了一些方法,但是注意看!

/**
 * SPI for cache providers.
 * 
 * One instance of cache will be created for each namespace.
 * 
 * The cache implementation must have a constructor that receives the cache id as an String parameter.
 * 
 * MyBatis will pass the namespace as id to the constructor.
 * 
 * <pre>
 * public MyCache(final String id) {
 *  if (id == null) {
 *    throw new IllegalArgumentException("Cache instances require an ID");
 *  }
 *  this.id = id;
 *  initialize();
 * }
 * </pre>
 *
 * @author Clinton Begin
 */

        这个接口的头顶的这段注释非常重要,它是这样说的,每一个namespace都将会有这样的一个实例。但是呢,这个实现接口的实现类必须有他要求的这个构造方法,这个构造方法呢实际上会接受一个id,这个id就是缓存时候的标示。
最后,还给了一段代码描述之。
        然后仔细的看下面的方法,无非就是放入缓存,得到缓存内容,移除缓存、清掉缓存全部内容、换区缓存的大小、还有就是读写加锁。
        然后,我们就照猫画虎来写一个呗!实际上,我们不着急动手,你知道的,


6


        上面的截图是我们的mybytis给我们的官方的一个简单实现,让我们去研究研究,然后开始动手。

/**
 *    Copyright 2009-2015 the original author or authors.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
package org.apache.ibatis.cache.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;

import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;

/**
 * @author Clinton Begin
 */
public class PerpetualCache implements Cache {

  private String id;

  private Map<Object, Object> cache = new HashMap<Object, Object>();

  public PerpetualCache(String id) {
    this.id = id;
  }

  @Override
  public String getId() {
    return id;
  }

  @Override
  public int getSize() {
    return cache.size();
  }

  @Override
  public void putObject(Object key, Object value) {
    cache.put(key, value);
  }

  @Override
  public Object getObject(Object key) {
    return cache.get(key);
  }

  @Override
  public Object removeObject(Object key) {
    return cache.remove(key);
  }

  @Override
  public void clear() {
    cache.clear();
  }

  @Override
  public ReadWriteLock getReadWriteLock() {
    return null;
  }

  @Override
  public boolean equals(Object o) {
    if (getId() == null) {
      throw new CacheException("Cache instances require an ID.");
    }
    if (this == o) {
      return true;
    }
    if (!(o instanceof Cache)) {
      return false;
    }

    Cache otherCache = (Cache) o;
    return getId().equals(otherCache.getId());
  }

  @Override
  public int hashCode() {
    if (getId() == null) {
      throw new CacheException("Cache instances require an ID.");
    }
    return getId().hashCode();
  }
}

        实际上面的代码很好看懂,那就是利用HashMap做缓存,阿偶,实际上我们只要把这个里面的写入HashMap和读取的操作换成别的一种存储方式,当然,想换成什么是你的自由。我们不就实现了二级缓存的自定义。

总结

        好了,马上就要吃饭了。今天的话利用早上的这点时间详细的看了下Mybatis二级缓存为我们预留的接口,然后看了其默认的实现类。官方的教材才是最完整的。下一篇我们将会来实现redis作为Mybatis二级缓存。敬请期待!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值