一级缓存

一级缓存默认是开启的,生命周期和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);
    }

最新文章

  1. Maven远程仓库的认证
  2. 曲演杂坛--使用CTE时踩的小坑:No Join Predicate
  3. UrlRewriteFilter
  4. 安装vim
  5. JS判断form内所有表单是否为空
  6. asp.net在word页眉插入条形码
  7. 通过枚举enum实现单例设计
  8. Docker 总结
  9. 【转】请求处理机制其二:Django中间件的解析
  10. 优化UI控件 【译】
  11. JavaScript面向对象之Windows对象
  12. 你懂AI吗(1)
  13. RabbitMQ教程C#版 - Hello World
  14. (译文)JavaScript基础——JavaScript中的深拷贝
  15. FC105 FC106 Scale功能块使用说明
  16. Window快捷键
  17. Linux目录结构 重要目录结构详细
  18. JIRA 资源
  19. 微信小程序开发之IOS/Android兼容坑(持续更新)
  20. [转]Java的文件读写操作

热门文章

  1. 联赛模拟测试22 B. 分组配对 倍增+二分
  2. 两个有序数列找第k小
  3. 栈&amp;队列&amp;并查集&amp;哈希表(julyedu网课整理)
  4. SQL Server双机热备之发布、订阅实现实时同步
  5. Linux 系统编程 学习:008-基于socket的网络编程3:基于 TCP 的通信
  6. 参悟python元类(又称metaclass)系列实战(一)
  7. 用Matlab对导出的数据进行可视化
  8. notepad++覆盖了eclipse的快捷键
  9. 2012年游戏软件开发独立本科段01B0815自考科目教材
  10. 一看就懂的MySQL的FreeList机制