//当调用 Mapper 所有的方法时,将都交由Proxy 中的 invoke 处理:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (!OBJECT_METHODS.contains(method.getName())) {
final Class declaringInterface = findDeclaringInterface(proxy, method);
// 最终交由 MapperMethod 类处理数据库操作,初始化 MapperMethod 对象
final MapperMethod mapperMethod = new MapperMethod(declaringInterface, method, sqlSession);
// 执行 mapper method,返回执行结果
final Object result = mapperMethod.execute(args);
....
return result;
}
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
public Object execute(Object[] args) throws SQLException {
Object result;
// 根据不同的操作类别,调用 DefaultSqlSession 中的执行处理
if (SqlCommandType.INSERT == type) {
Object param = getParam(args);
result = sqlSession.insert(commandName, param);
} else if (SqlCommandType.UPDATE == type) {
Object param = getParam(args);
result = sqlSession.update(commandName, param);
} else if (SqlCommandType.DELETE == type) {
Object param = getParam(args);
result = sqlSession.delete(commandName, param);
} else if (SqlCommandType.SELECT == type) {
if (returnsList) {
result = executeForList(args);
} else {
Object param = getParam(args);
result = sqlSession.selectOne(commandName, param);
}
} else {
throw new BindingException("Unkown execution method for: " + commandName);
}
return result;
}
public Object selectOne(String statement, Object parameter) {
List list = selectList(statement, parameter);
if (list.size() == 1) {
return list.get(0);
}
...
}
public List selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
// 如果启动用了Cache 才调用 CachingExecutor.query,反之则使用 BaseExcutor.query 进行数据库查询
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
public List query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
// 执行器已关闭
if (closed) throw new ExecutorException("Executor was closed.");
List list;
try {
queryStack++;
// 创建缓存Key
CacheKey key = createCacheKey(ms, parameter, rowBounds);
// 从本地缓存在中获取该 key 所对应 的结果集
final List cachedList = (List) localCache.getObject(key);
// 在缓存中找到数据
if (cachedList != null) {
list = cachedList;
} else { // 未从本地缓存中找到数据,开始调用数据库查询
//为该 key 添加一个占位标记
localCache.putObject(key, EXECUTION_PLACEHOLDER);
try {
// 执行子类所实现的数据库查询 操作
list = doQuery(ms, parameter, rowBounds, resultHandler);
} finally {
// 删除该 key 的占位标记
localCache.removeObject(key);
}
// 将db中的数据添加至本地缓存中
localCache.putObject(key, list);
}
} finally {
queryStack--;
}
// 刷新当前队列中的所有 DeferredLoad实例,更新 MateObject
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
}
return list;
}
public List query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
if (ms != null) {
// 获取二级缓存实例
Cache cache = ms.getCache();
if (cache != null) {
flushCacheIfRequired(ms);
// 获取 读锁( Read锁可由多个Read线程同时保持)
cache.getReadWriteLock().readLock().lock();
try {
// 当前 Statement 是否启用了二级缓存
if (ms.isUseCache()) {
// 将创建 cache key 委托给 BaseExecutor 创建
CacheKey key = createCacheKey(ms, parameterObject, rowBounds);
final List cachedList = (List) cache.getObject(key);
// 从二级缓存中找到缓存数据
if (cachedList != null) {
return cachedList;
} else {
// 未找到缓存,很委托给 BaseExecutor 执行查询
List list = delegate.query(ms, parameterObject, rowBounds, resultHandler);
tcm.putObject(cache, key, list);
return list;
}
} else { // 没有启动用二级缓存,直接委托给 BaseExecutor 执行查询
return delegate.query(ms, parameterObject, rowBounds, resultHandler);
}
} finally {
// 当前线程释放 Read 锁
cache.getReadWriteLock().readLock().unlock();
}
}
}
return delegate.query(ms, parameterObject, rowBounds, resultHandler);
}
private void cacheElement(XNode context) throws Exception {
if (context != null) {
// 基础缓存类型
String type = context.getStringAttribute("type", "PERPETUAL");
Class typeClass = typeAliasRegistry.resolveAlias(type);
// 排除算法缓存类型
String eviction = context.getStringAttribute("eviction", "LRU");
Class evictionClass = typeAliasRegistry.resolveAlias(eviction);
// 缓存自动刷新时间
Long flushInterval = context.getLongAttribute("flushInterval");
// 缓存存储实例引用的大小
Integer size = context.getIntAttribute("size");
// 是否是只读缓存
boolean readWrite = !context.getBooleanAttribute("readOnly", false);
Properties props = context.getChildrenAsProperties();
// 初始化缓存实现
builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, props);
}
}
public Cache useNewCache(Class typeClass,
Class evictionClass,
Long flushInterval,
Integer size,
boolean readWrite,
Properties props) {
typeClass = valueOrDefault(typeClass, PerpetualCache.class);
evictionClass = valueOrDefault(evictionClass, LruCache.class);
// 这里构建 Cache 实例采用 Builder 模式,每一个 Namespace 生成一个 Cache 实例
Cache cache = new CacheBuilder(currentNamespace)
// Builder 前设置一些从XML中解析过来的参数
.implementation(typeClass)
.addDecorator(evictionClass)
.clearInterval(flushInterval)
.size(size)
.readWrite(readWrite)
.properties(props)
// 再看下面的 build 方法实现
.build();
configuration.addCache(cache);
currentCache = cache;
return cache;
}
public Cache build() {
setDefaultImplementations();
// 创建基础缓存实例
Cache cache = newBaseCacheInstance(implementation, id);
setCacheProperties(cache);
// 缓存排除算法初始化,并将其委托至基础缓存中
for (Class<? extends Cache> decorator : decorators) {
cache = newCacheDecoratorInstance(decorator, cache);
setCacheProperties(cache);
}
// 标准装饰器缓存设置,如LoggingCache之类,同样将其委托至基础缓存中
cache = setStandardDecorators(cache);
// 返回最终缓存的责任链对象
return cache;
}
public void putObject(Object key, Object object) {
acquireWriteLock(); // 获取 Write 锁
try {
delegate.putObject(key, object); // 委托给下一个 Cache 执行 put 操作
} finally {
releaseWriteLock(); // 释放 Write 锁
}
}
public Object getObject(Object key) {
acquireReadLock();
try {
return delegate.getObject(key);
} finally {
releaseReadLock();
}
}
public Object getObject(Object key) {
requests++; // 每调用一次该方法,则获取次数+1
final Object value = delegate.getObject(key);
if (value != null) { // 命中! 命中+1
hits++;
}
if (log.isDebugEnabled()) {
// 输出命中率。计算方法为: hits / requets 则为命中率
log.debug("Cache Hit Ratio [" + getId() + "]: " + getHitRatio());
}
return value;
}
public void putObject(Object key, Object object) {
// PO 类需要实现 Serializable 接口
if (object == null || object instanceof Serializable) {
delegate.putObject(key, serialize((Serializable) object));
} else {
throw new CacheException("SharedCache failed to make a copy of a non-serializable object: " + object);
}
}
public Object getObject(Object key) {
Object object = delegate.getObject(key);
// 获取数据时对 二进制数据进行反序列化
return object == null ? null : deserialize((byte[]) object);
}
public LruCache(Cache delegate) {
this.delegate = delegate;
setSize(1024); // 设置 map 默认大小
}
public void setSize(final int size) {
// 设置其 capacity 为size, 其 factor 为.75F
keyMap = new LinkedHashMap(size, .75F, true) {
// 覆盖该方法,当每次往该map 中put 时数据时,如该方法返回 True,便移除该map中使用最少的Entry
// 其参数 eldest 为当前最老的 Entry
protected boolean removeEldestEntry(Map.Entry eldest) {
boolean tooBig = size() > size;
if (tooBig) {
eldestKey = eldest.getKey(); //记录当前最老的缓存数据的 Key 值,因为要委托给下一个 Cache 实现删除
}
return tooBig;
}
};
}
public void putObject(Object key, Object value) {
delegate.putObject(key, value);
cycleKeyList(key); // 每次 put 后,调用移除最老的 key
}
// 看看当前实现是否有 eldestKey, 有的话就调用 removeObject ,将该key从cache中移除
private void cycleKeyList(Object key) {
keyMap.put(key, key); // 存储当前 put 到cache中的 key 值
if (eldestKey != null) {
delegate.removeObject(eldestKey);
eldestKey = null;
}
}
public Object getObject(Object key) {
keyMap.get(key); // 便于 该 Map 统计 get该key的次数
return delegate.getObject(key);
}
package com.xx.core.plugin.mybatis;
import java.util.LinkedList;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.ibatis.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.xx.core.memcached.JMemcachedClientAdapter;
import com.xx.core.memcached.service.CacheService;
import com.xx.core.memcached.service.MemcachedService;
/**
* Cache adapter for Memcached.
*
* @author denger
*/
public class MemcachedCache implements Cache {
// Sf4j logger reference
private static Logger logger = LoggerFactory.getLogger(MemcachedCache.class);
/** The cache service reference. */
protected static final CacheService CACHE_SERVICE = createMemcachedService();
/** The ReadWriteLock. */
private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private String id;
private LinkedList<String> cacheKeys = new LinkedList<String>();
public MemcachedCache(String id) {
this.id = id;
}
// 创建缓存服务类,基于java-memcached-client
protected static CacheService createMemcachedService() {
JMemcachedClientAdapter memcachedAdapter;
try {
memcachedAdapter = new JMemcachedClientAdapter();
} catch (Exception e) {
String msg = "Initial the JMmemcachedClientAdapter Error.";
logger.error(msg, e);
throw new RuntimeException(msg);
}
return new MemcachedService(memcachedAdapter);
}
@Override
public String getId() {
return this.id;
}
// 根据 key 从缓存中获取数据
@Override
public Object getObject(Object key) {
String cacheKey = String.valueOf(key.hashCode());
Object value = CACHE_SERVICE.get(cacheKey);
if (!cacheKeys.contains(cacheKey)){
cacheKeys.add(cacheKey);
}
return value;
}
@Override
public ReadWriteLock getReadWriteLock() {
return this.readWriteLock;
}
// 设置数据至缓存中
@Override
public void putObject(Object key, Object value) {
String cacheKey = String.valueOf(key.hashCode());
if (!cacheKeys.contains(cacheKey)){
cacheKeys.add(cacheKey);
}
CACHE_SERVICE.put(cacheKey, value);
}
// 从缓存中删除指定 key 数据
@Override
public Object removeObject(Object key) {
String cacheKey = String.valueOf(key.hashCode());
cacheKeys.remove(cacheKey);
return CACHE_SERVICE.delete(cacheKey);
}
//清空当前 Cache 实例中的所有缓存数据
@Override
public void clear() {
for (int i = 0; i < cacheKeys.size(); i++){
String cacheKey = cacheKeys.get(i);
CACHE_SERVICE.delete(cacheKey);
}
cacheKeys.clear();
}
@Override
public int getSize() {
return cacheKeys.size();
}
}
<cache eviction="LRU" type="com.xx.core.plugin.mybatis.MemcachedCache" />
memcached -c 2000 -p 11211 -vv -U 0 -l 192.168.1.2 -v
@Test
public void testSelectById() {
Long pid = 100L;
Product dbProduct = productMapper.selectByID(pid);
Assert.assertNotNull(dbProduct);
Product cacheProduct = productMapper.selectByID(pid);
Assert.assertNotNull(cacheProduct);
productMapper.updateName("IPad", pid);
Product product = productMapper.selectByID(pid);
Assert.assertEquals(product.getName(), "IPad");
}
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) | 黑马程序员IT技术论坛 X3.2 |