前言
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就是缓存时候的标示。
最后,还给了一段代码描述之。
然后仔细的看下面的方法,无非就是放入缓存,得到缓存内容,移除缓存、清掉缓存全部内容、换区缓存的大小、还有就是读写加锁。
然后,我们就照猫画虎来写一个呗!实际上,我们不着急动手,你知道的,
上面的截图是我们的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二级缓存。敬请期待!
本文探讨MyBatis框架中的二级缓存机制,解析其核心接口与默认实现,并为自定义缓存方案奠定基础。
4548

被折叠的 条评论
为什么被折叠?



