zoukankan      html  css  js  c++  java
  • 讨论Spring整合Mybatis时一级缓存失效得问题

    问题

    1、学习测试时发现了一级缓存并没有生效,先看案例:
    setting配置:

      <settings>
            <!-- (1) 提供可控制Mybatis框架运行行为的属性信息 -->
            <setting name="lazyLoadingEnabled" value="false" />
            <setting name="logImpl" value="STDOUT_LOGGING" />
            <setting name="localCacheScope" value="SESSION"/>
        </settings>
    

    测试代码:

       @Test
        public void test1(){
            try(SqlSession sqlSession = sessionFactory.openSession();){
                 GoodsMapper goodsMapper = sqlSession.getMapper(GoodsMapper.class);
                 Goods goods = goodsMapper.getGoodsById(1,"电脑2");
                  Goods goods2 = goodsMapper.getGoodsById(1,"电脑2");
            }
        }
    
        @Autowired
        private GoodsMapper goodsMapper;
    
    
        @Test
        public void test2(){
            Goods goods = goodsMapper.getGoodsById(1,"电脑2");
            Goods goods2 = goodsMapper.getGoodsById(1,"电脑2");
        }
    

    问题分析

    首先我们都知道一级缓存的作用范围有两种,一种是sqlSession,一种是STATEMENT。我们看test2方法,用的都是同一个mapper,按理说是应该只查询一次的啊,难道同一个mapper的sqlSession不一样。紧接着我试了test1方法,用的也都是同一个mapper,发现只查询了一次数据库。难道这两种方法有不一样的地方吗?
    

    答案就在MapperProxy类当中,我们打断点执行test1方法,我们发现他的sqlSession类型是DefaultSqlSession

    然后再执行test2方法,我们发现他的sqlSession类型是SqlSessionTemplate

    他们的差别找到了,失效的原因多半就是SqlSessionTemplate造成的,SqlSessionTemplate类里有一个SqlSessionInterceptor,我们看他的invoke方法,代码如下:

    private class SqlSessionInterceptor implements InvocationHandler {
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
          SqlSession sqlSession = getSqlSession(
              SqlSessionTemplate.this.sqlSessionFactory,
              SqlSessionTemplate.this.executorType,
              SqlSessionTemplate.this.exceptionTranslator);
          try {
            Object result = method.invoke(sqlSession, args);
            if (!isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
              // force commit even on non-dirty sessions because some databases require
              // a commit/rollback before calling close()
              sqlSession.commit(true);
            }
            return result;
          } catch (Throwable t) {
            Throwable unwrapped = unwrapThrowable(t);
            if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
              // release the connection to avoid a deadlock if the translator is no loaded. See issue #22
              closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
              sqlSession = null;
              Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException) unwrapped);
              if (translated != null) {
                unwrapped = translated;
              }
            }
            throw unwrapped;
          } finally {
            if (sqlSession != null) {
              closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
            }
          }
        }
      }
    
    

    此时我们发现sqlSession是通过invoke方法里的getSqlSession方法重新赋值了,而我打断点发现,同一个mapper调同样的方法获得的sqlSession是不一样的,既然不一样,那当然读不到缓存了。

    而DefaultSqlSession则是直接执行查询方法,是同一个sqlSession。所以读到了缓存。

  • 相关阅读:
    C++类继承内存布局(二)
    C++类继承内存布局(一)
    排序算法
    python 文件路径问题
    python map对象
    python reduce() 函数
    python eval 用法
    PyCharm引入自定义类报错
    Python中的lambda的简单介绍
    python time模块和datetime模块
  • 原文地址:https://www.cnblogs.com/javammc/p/11324503.html
Copyright © 2011-2022 走看看