mybatis之缓存模块

Posted 我爱看明朝

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mybatis之缓存模块相关的知识,希望对你有一定的参考价值。

mybatis之缓存模块

mybatis中存在一级(默认开启)、二级缓存。缓存可以加快查询速度,减少连接db的次数。

cache模块属于mybatis的基础支持层。位于org.apache.ibatis.cache包下。

--------org.apache.ibatis.cache
-------------------------------decorators
-----------------------------------------BlockingCache
-----------------------------------------FifoCache
-----------------------------------------LoggingCache
-----------------------------------------LruCache
-----------------------------------------ScheduledCache
-----------------------------------------SerializedCache
-----------------------------------------SoftCache
-----------------------------------------SynchronizedCache
-----------------------------------------TransactionalCache
-----------------------------------------WeakCache
-------------------------------impl
-----------------------------------PerpetualCache
------------------------------Cache

Cache PerpetualCache BlockingCache FifoCache LoggingCache LruCache ScheduledCache SerializedCache SoftCache SynchronizedCache TransactionalCache WeakCache

Cache

缓存的顶级接口

public interface Cache {
    // 得到缓存的id
    String getId();
    // 插入缓存
    void putObject(Object key, Object value);
    // 查询到缓存
    Object getObject(Object key);
    // 删除缓存
    Object removeObject(Object key);
    //清理这个缓存实例
    void clear();
    // 这个方法可选,不是核心调用方法,查询缓存key的个数
    int getSize();
    //
    ReadWriteLock getReadWriteLock();
}   

PerpetualCache

缓存的基础实现(实现了基本的缓存功能,底层数据结构使用HashMap)

一级缓存是会话级别的缓存(SqlSession)。

public class PerpetualCache implements Cache {

    private final String id;
    // 存储缓存底层数据结构使用hashMap
    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();
  }
}

BlockingCache

BlockingCache是带有阻塞功能的缓存装饰器。

public class BlockingCache implements Cache {

    //超时时间
    private long timeout;
    // 被装饰的缓存
    private final Cache delegate;
    // 每一个Key拥有一把可重入锁
    private final ConcurrentHashMap<Object, ReentrantLock> locks;
    //构造器,装饰其他cache对象
    public BlockingCache(Cache delegate) {
      this.delegate = delegate;
      this.locks = new ConcurrentHashMap<Object, ReentrantLock>();
    }

    @Override
    public String getId() {
      return delegate.getId();
    }

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

    // 插入Key的缓存,插入完毕同时释放锁
    @Override
    public void putObject(Object key, Object value) {
      try {
        delegate.putObject(key, value);
      } finally {
        releaseLock(key);
      }
    }

  // 查询key的缓存
  @Override
  public Object getObject(Object key) {
    //获取到key的锁
    acquireLock(key);
    // 查询key缓存的值
    Object value = delegate.getObject(key);
    //如果value不为null,则释放锁,返回值,否则一直持有锁,知道key有值插入到缓存
    if (value != null) {
      releaseLock(key);
    }        
    return value;
  }

  @Override
  public Object removeObject(Object key) {
    // despite of its name, this method is called only to release locks
    releaseLock(key);
    return null;
  }

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

  @Override
  public ReadWriteLock getReadWriteLock() {
    return null;
  }
  
  //查询Key持有的锁,如果没有则创建新锁
  private ReentrantLock getLockForKey(Object key) {
    ReentrantLock lock = new ReentrantLock();
    ReentrantLock previous = locks.putIfAbsent(key, lock);
    return previous == null ? lock : previous;
  }
  
  private void acquireLock(Object key) {
    Lock lock = getLockForKey(key);
    if (timeout > 0) {
      try {
        boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
        if (!acquired) {
          throw new CacheException("Couldn't get a lock in " + timeout + " for the key " +  key + " at the cache " + delegate.getId());  
        }
      } catch (InterruptedException e) {
        throw new CacheException("Got interrupted while trying to acquire lock for key " + key, e);
      }
    } else {
      lock.lock();
    }
  }
  
  private void releaseLock(Object key) {
    ReentrantLock lock = locks.get(key);
    if (lock.isHeldByCurrentThread()) {
      lock.unlock();
    }
  }

  带你彻底搞懂MyBatis的底层实现之缓存模块(Cache)-吊打面试官必备技能

带你彻底搞懂MyBatis的底层实现之缓存模块(Cache)-吊打面试官必备技能

Mybatis 学习笔记总结

myBatis组件之缓存实现及使用

mybatis框架之装饰模式

mybatis学习笔记(13)-查询缓存之二级缓存