您的位置:首页 > 其它

Mybatis的缓存机制

2017-11-04 00:00 267 查看
之前写了一个Mybatis的读写分离插件,今天使用过程中发现1个奇怪的问题

就是如果在一个线程里同时调用某个函数2次,比如这样的

// Select
role = userMapper.getRole0(13);
LOGGER.info("---------------------------------------------------");
role = userMapper.getRole0(13);

发现第2次没有走我之前的插件机制,然后我 debug了一下,发现问题在这里

Step completed: "thread=main", org.apache.ibatis.executor.BaseExecutor.query(), line=152 bci=68
152          list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;

main[1] !!
next
>
Step completed: "thread=main", org.apache.ibatis.executor.BaseExecutor.query(), line=153 bci=91
153          if (list != null) {

main[1] !!
next
>
Step completed: "thread=main", org.apache.ibatis.executor.BaseExecutor.query(), line=154 bci=96
154            handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);

貌似走了本地缓存,打上断点看看

stop in org.apache.ibatis.executor.BaseExecutor.query

观察2次有什么区别,现象如下:

第1次执行

Step completed: "thread=main", org.apache.ibatis.executor.BaseExecutor.query(), line=152 bci=68
152          list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;

main[1] print localCache
localCache = "org.apache.ibatis.cache.impl.PerpetualCache@c2f3a6f7"
main[1] next
>
Step completed: "thread=main", org.apache.ibatis.executor.BaseExecutor.query(), line=153 bci=91
153          if (list != null) {

main[1] print list
list = null

第一次,肯定是找不到的



果然走了本地缓存,所以问题也找到了,根本原因就是

@SuppressWarnings("unchecked")
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 && ms.isFlushCacheRequired()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {//本地可以有缓存
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {//开关在这里
// issue #482
clearLocalCache();
}
}
return list;
}

问题找到了,那么

onfiguration.getLocalCacheScope()怎么控制呢?

/**
*    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.session;

/**
* @author Eduardo Macarron
*/
public enum LocalCacheScope {
SESSION,STATEMENT
}

默认是session级别的,所以这里我要改成statement级别的!!!

=============怎么改?



所以,只要在配置文件里增加

<setting name="localCacheScope" value="STATEMENT" />

测试通过!不会再用本地缓存了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  MyBatis