一级缓存

一级缓存默认是开启的,生命周期和SqlSession相同。一个会话中每次执行一个查询操作时,会先查询二级缓存,如果二级缓存没查到或者二级缓存未开启就会从一级缓存中查询,如果一级缓存也未查到就从数据库中查询

一级缓存使用条件
  1. 必须是相同的SQL语句
  2. 必须是相同的参数
  3. 必须是同一个会话
  4. 必须是同一个namespace即相同的mapper接口
  5. 必须是同一个mapper接口中的同一个方法
  6. 查询之前没有增删改操作(不管操作是否成功,只要进行了增删改操作就会清空一级缓存)
  7. 查询之前没有执行sqlSession.clearCache()方法

二级缓存

二级缓存需要我们手动开启,生命周期和SqlSessionFactory相同。可以适用于多个session之间共享数据

开启二级缓存
  1. 在mapper接口上面写@CacheNamespace注解,需要注意的是如果采用了注解方式,那么写SQL语句也需要使用注解,否则二级缓存不会生效

    @CacheNamespace(

    ​ implementation = PerpetualCache.class, // 缓存实现 Cache接口 实现类

    ​ eviction = LruCache.class,// 缓存算法

    ​ flushInterval = 60000, // 刷新间隔时间 毫秒

    ​ size = 1024, // 最大缓存引用对象

    ​ readWrite = true, // 是否可写

    ​ blocking = false // 是否阻塞

    )

  2. 在xxxMapper.xml文件中定义cache标签

二级缓存使用条件
  1. 当会话提交或者关闭时才会填充数据到二级缓存中
  2. 必须是在同一个命名空间下
  3. 必须是相同的statment,即同一个mapper接口的同一个方法
  4. 必须是相同的SQL语句和参数
  5. 如果readWrite=true ,实体类必须实现Serializable 接口
二级缓存清空条件
  1. 任何一种增删改操作 都会清空整个namespace 中的缓存
  2. 只有修改会话提交之后 才会执行清空操作

调用链

  1. 顶层api调用

    PersonMapper mapper = session.getMapper(PersonMapper.class);
    Person person1 = mapper.selectPersonById(1);
  2. 不管是调用select方法还是update方法,都会进入DefaultSqlSession类中,并调用对应方法

    /*
    DefaultSqlSession > selectList() getMappedStatement(statement) 方法,statement即为namespace + selectId。通过configuration获取mapperedStatement,MapperedStatement封装了id、sqlSource、resultMap、paramType等。 通过executor调用下一层的executor执行器执行
    */ @Override
    public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
    MappedStatement ms = configuration.getMappedStatement(statement);
    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();
    }
    }
  3. 然后进入CacheExecutor中尝试获取二级缓存

    /*
    CacheExecutor > query() 获取二级缓存的key值
    */
    @Override
    public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { BoundSql boundSql = ms.getBoundSql(parameterObject);
    CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
    return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    }
     /*
    CacheExecutor > query() 尝试获取二级缓存的值
    */ @Override
    public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
    throws SQLException {
    Cache cache = ms.getCache(); // 获取二级缓存
    if (cache != null) { //如果cache为空,说明未开启二级缓存
    flushCacheIfRequired(ms);
    if (ms.isUseCache() && resultHandler == null) {
    ensureNoOutParams(ms, boundSql);
    @SuppressWarnings("unchecked")
    List<E> list = (List<E>) tcm.getObject(cache, key);
    //如果未从二级缓存获取到对应的值,就走一级缓存
    if (list == null) {
    list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    //将值存入二级缓存中
    tcm.putObject(cache, key, list); // issue #578 and #116
    }
    return list;
    }
    }
    //如果没有获取二级缓存,就尝试去获取一级缓存
    return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
    1. 如果二级缓存没有开启或者未从二级缓存中获取到值,就走一级缓存
    /*
    BaseExecutor > query()
    */
    ......
    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--;
    } ......从缓存中获取值
  4. 不管是二级缓存,还是一级缓存都是从perpetualCache类中的HashMap中进行取值和赋值等操作

     /*
    PerpetualCache > getObject()
    */ @Override
    public Object getObject(Object key) {
    return cache.get(key);
    }

MyBatis的一二级缓存的更多相关文章

  1. 认识Mybatis的一二级缓存

    认识Mybatis的一二级缓存 一次完整的数据库请求,首先根据配置文件生成SqlSessionFactory,再通过SqlSessionFactory开启一次SqlSession,在每一个SqlSes ...

  2. java架构之路-(源码)mybatis的一二级缓存问题

    上次博客我们说了mybatis的基本使用,我们还捎带提到一下Mapper.xml中的select标签的useCache属性,这个就是设置是否存入二级缓存的. 回到我们正题,经常使用mybatis的小伙 ...

  3. 【MyBatis源码解析】MyBatis一二级缓存

    MyBatis缓存 我们知道,频繁的数据库操作是非常耗费性能的(主要是因为对于DB而言,数据是持久化在磁盘中的,因此查询操作需要通过IO,IO操作速度相比内存操作速度慢了好几个量级),尤其是对于一些相 ...

  4. mybatis 源码分析(四)一二级缓存分析

    本篇博客主要讲了 mybatis 一二级缓存的构成,以及一些容易出错地方的示例分析: 一.mybatis 缓存体系 mybatis 的一二级缓存体系大致如下: 首先当一二级缓存同时开启的时候,首先命中 ...

  5. Mybatis学习(6)动态加载、一二级缓存

    一.动态加载: resultMap可以实现高级映射(使用association.collection实现一对一及一对多映射),association.collection具备延迟加载功能. 需求: 如 ...

  6. Mybatis一二级缓存的理解

        频繁的数据库操作是非常耗费性能的(主要是因为对于DB而言,数据是持久化在磁盘中的,因此查询操作需要通过IO,IO操作速度相比内存操作速度慢了好几个量级),尤其是对于一些相同的查询语句,完全可以 ...

  7. [原创]关于mybatis中一级缓存和二级缓存的简单介绍

    关于mybatis中一级缓存和二级缓存的简单介绍 mybatis的一级缓存: MyBatis会在表示会话的SqlSession对象中建立一个简单的缓存,将每次查询到的结果结果缓存起来,当下次查询的时候 ...

  8. MyBatis学习--查询缓存

    简介 以前在使用Hibernate的时候知道其有一级缓存和二级缓存,限制ORM框架的发展都是互相吸收其他框架的优点,在Hibernate中也有一级缓存和二级缓存,用于减轻数据压力,提高数据库性能. m ...

  9. Mybatis的二级缓存配置

    一个项目中肯定会存在很多共用的查询数据,对于这一部分的数据,没必要每一个用户访问时都去查询数据库,因此配置二级缓存将是非常必要的.  Mybatis的二级缓存配置相当容易,要开启二级缓存,只需要在你的 ...

随机推荐

  1. 第六章 DQL 数据查询语言

    一.select 简单查询命令 #1.查询表中所有的数据 mysql> select * from test.student; #2.查看所有数据之前,先查看数据量 mysql> sele ...

  2. react-native 签名

    完成项目时,我们需要将项目打包成一个apk,方便测试以及发布版本. 这时,需要把js代码和图片资源都放进apk中, 并且发布版本还需要签名,今天把这一系列操作记录下来. 一.生成离线bundle包 离 ...

  3. django 连接 mysql数据库

    1.安装mysqlclient pip install mysqlclient 或 pycharm --> File --> settings --> Project: (项目名称) ...

  4. oracle truncate table recover(oracle 如何拯救误操作truncate的表)

     生产上肯定是容易脑袋发热,truncate一张表,立马的心跳加速,眼神也不迷糊了,搞错了,完了-- 那么,truncate表后,能不能进行恢复? truncate操作是比较危险的操作,不记录redo ...

  5. 安卓快速关机APP

    目录 自说自话 使用方法 自说自话 像我这样每天晚上睡觉关机的人不知道有多少,反正我每天都有关机的需求.因此我特别讨厌长按关机键进行关机,感觉浪费我好几秒的生命. 因此我开发了这款APP,主要是自用, ...

  6. vue踩坑

    1. 双向绑定的对象 改变或新增其属性 DOM不刷新问题 var obj = { "attr1": "1", "attr2": [2] }; ...

  7. Pyston v2.0 发布,解决 Python 慢速的救星

    Pyston 自从 2017 年发布 0.6.1 版本后,已经淡出了人们的视线三年多了,导致现在新人都很少听过它的大名. 前两天(2020年10月28日)Pyston 在官方博客上(https://b ...

  8. 回顾MySql的一些基本的增删改查

    ---恢复内容开始--- 回顾数据库的一些简单的增删查改的操作语法与注意点,来自菜鸟教程https://www.runoob.com/mysql/mysql-tutorial.html 关于数据库的操 ...

  9. 最全总结 | 聊聊 Python 办公自动化之 Excel(下)

    1. 前言 前面谈到 Python 处理 Excel 文件最常见的两种方式,即:xlrd/xlwt.openpyxl ​其中, xlrd/xlwt 这一组合,xlrd 可以负责读取数据,而 xlwt ...

  10. C++ 基础 3:类和对象

    1 类和对象 1.1 类定义 类定义是以关键字 class 开头,后跟类的名称.类的主体是包含在一对花括号中.类定义后必须跟着一个分号或一个声明列表.例如,我们使用关键字 class 定义 Box 数 ...