Mybatis的缓存机制

作者描述了在使用自定义Mybatis读写分离插件时遇到的问题,发现第二次查询未走插件,原因是依赖了本地缓存。通过分析代码,发现需要将`configuration.getLocalCacheScope()`改为`STATEMENT`级别以解决此问题,解决方案是在配置文件中添加相应设置。
摘要由CSDN通过智能技术生成

之前写了一个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" />

测试通过!不会再用本地缓存了。

作者:强子大叔的码田

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小学生拉登

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值