摘要

主要是分析的一下Mybatis的一级缓存和二级缓存的原理和源码的操作。每一次在和数据库进行会话的过程中,MyBatis 都会创建一个SqlSession对象。同一次会话期间,只要是查询过的数据,都会保存在当前SqlSession对象的一个Map中。所以在一次会话的过程中,如果我们对一条查询SQL 语句进行了多次执行,经过判断后和之前执行的查询语句相同,并且在缓存中存在该SQL 语句的执行结果,那么这次查询就不会再从数据库中获取数据,而是直接从缓存中获取数据。因为一级缓存是建立在SqlSession对象中的,所以也可以说一级缓存是一个SqlSession级别的缓存。在默认的情况下,一级缓存是开启的。MyBatis 提供了二级缓存机制,二级缓存是一个namespace级别的缓存,相对于一级缓存而言,二级缓存允许跨SqlSession工作,因此二级缓存的作用范围更大。每个SqlSession在执行查询操作的时候,都会将查询的结果放在当前会话的一级缓存中。如果当前会话关闭,一级缓存中的数据会被保存在二级缓存中。因此二级缓存是在一级缓存的基础上进行扩展的,不同的namespace查出的数据都会将数据存在自己对应的缓存中,这些缓存信息使用Map存储。

一级缓存测试

mapper 接口:

    Employee getEmpById(Integer id);

SQL 映射文件:

    <select id="getEmpById" resultType="com.jas.mybatis.bean.Employee">SELECT  * FROM t_employee WHERE id = #{id}</select>

测试代码:

    // 用于创建SqlSession 对象private SqlSession getSqlSession() throws IOException {String resource = "mybatis-config.xml";InputStream is = Resources.getResourceAsStream(resource);SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);SqlSession sqlSession = sqlSessionFactory.openSession();return sqlSession;}@Testpublic void testCache() throws IOException {SqlSession sqlSession = getSqlSession();EmployeeMapper employeeMapper = sqlSession.getMapper(EmployeeMapper.class);// 从数据库中获得id 为1 的员工信息Employee employee1 = employeeMapper.getEmpById(1);System.out.println(employee1);// 再一次从数据库中获得id 为1 的员工信息Employee employee2 = employeeMapper.getEmpById(1);System.out.println(employee2);sqlSession.close();}

上面的测试过程中一共对id为1 的员工信息进行了两次查询,并且在中间过程中没有进行其他的操作,下面我们通过SQL 日志来看看执行的过程。

虽然我们执行了两次查询,但是从执行结果来看,其实只发送了一条SQL 语句,在第二次获得员工信息的时候并不是从数据库中获取数据,而是直接在一级缓存中获得数据,这就是一级缓存起到的作用。

一级缓存失效

我们知道,一级缓存是一个SqlSession级别的缓存,所以一级缓存在工作的过程中会有一定的局限。一级缓存失效的情况:

  • 1.只对当前SqlSession对象生效,对于其他的SqlSession来说一级缓存是不起作用的。
  • 2.是同一个SqlSession对象,但是执行的是不同条件的SQL 查询语句。
  • 3.同一个SqlSession对象执行同一条件的查询语句,但中间执行了增删改的操作,之前一级缓存中的数据会失效。如果执行的是不同条件的查询语句,一级缓存仍然生效,并且会把新的查询数据也加入到一级缓存中。
  • 4.多次相同查询语句在执行期间通过sqlSession.clearCache();方法清除了缓存。
  • 5.SqlSession 对象调用了close()方法,当前会话结束,一级缓存不再生效。

对于上面的几种情况,一级缓存都是不起作用的。所以在处理业务的时候要根据需求,具体分析能不能使用一级缓存。

一级缓存的生命周期

  • MyBatis在开启一个数据库会话时,会 创建一个新的SqlSession对象,SqlSession对象中会有一个新的Executor对象,Executor对象中持有一个新的PerpetualCache对象;当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。
  • 如果SqlSession调用了close()方法,会释放掉一级缓存PerpetualCache对象,一级缓存将不可用;
  • 如果SqlSession调用了clearCache(),会清空PerpetualCache对象中的数据,但是该对象仍可使用;
  • SqlSession中执行了任何一个update操作(update()、delete()、insert()) ,都会清空PerpetualCache对象的数据,但是该对象可以继续使用;

二级缓存

MyBatis 提供了二级缓存机制,二级缓存是一个namespace级别的缓存,相对于一级缓存而言,二级缓存允许跨SqlSession工作,因此二级缓存的作用范围更大。每个SqlSession在执行查询操作的时候,都会将查询的结果放在当前会话的一级缓存中。如果当前会话关闭,一级缓存中的数据会被保存在二级缓存中。因此二级缓存是在一级缓存的基础上进行扩展的,不同的namespace查出的数据都会将数据存在自己对应的缓存中,这些缓存信息使用Map存储。需要注意的地方是:MyBatis 在开启二级缓存的情况下,如果发出了一条SQL 查询语句,会先向二级缓存中查询是否有对应的缓存数据,如果没有再接着查询一级缓存中的数据,如果一级缓存中也没有对应的缓存数据,才会向数据库发送SQL。下面附一张蹩脚的二级缓存运行机制图。

实现二级缓存的步骤

  • 1.在MyBatis 全局配置文件中开启二级缓存的配置,默认也是开启的,建议自己设置为开启的。
  • 2.在对应的SQL 映射文件中加入<cache/>标签。
  • 3.将返回的JavaBean 数据类型的类实现Serializable(序列化)接口

二级缓存测试

MyBatis 全局配置文件:

    <!-- 配置二级缓存,默认也是开启的,建议手动设置一下 --><setting name="cacheEnabled" value="true"/>

POJO 实现序列化接口:

package com.jas.mybatis.bean;import java.io.Serializable;public class Department implements Serializable{private Integer id;private String departmentName;//省略get、set 与toString 方法
}

mapper 接口:

    Department getDeptById(Integer id);

SQL 映射文件:

    <!-- 在需要使用二级缓存的SQL 映射文件中添加 <cache/> 标签相关的一些参数介绍:eviction:缓存回收策略flushInterval:缓存刷新时间,单位是毫秒,默认不刷新size:可存储多少个缓存对象,只能是正整数,合理的设置可以防止内存泄漏readOnly:是否只读--><cache/><select id="getDeptById" resultType="com.jas.mybatis.bean.Department">SELECT id, dept_name departmentName FROM t_dept WHERE id = #{id}</select>

测试代码:

    // 用于返回SqlSessionFactory  对象private SqlSessionFactory getSqlSession() throws IOException {String resource = "mybatis-config.xml";InputStream is = Resources.getResourceAsStream(resource);return new SqlSessionFactoryBuilder().build(is);  }@Testpublic void secondLevelTest() throws IOException {SqlSessionFactory sqlSessionFactory = getSqlSession();//创建两个不同的会话SqlSession sqlSession1 = sqlSessionFactory.openSession();SqlSession sqlSession2 = sqlSessionFactory.openSession();DepatmentMapper depatmentMapper1 = sqlSession1.getMapper(DepatmentMapper.class);DepatmentMapper depatmentMapper2 = sqlSession2.getMapper(DepatmentMapper.class);Department department1 = depatmentMapper1.getDeptById(1);System.out.println(department1);    // 关闭当前的会话1, 否则二级缓存不起作用sqlSession1.close();Department department2 = depatmentMapper2.getDeptById(1);System.out.println(department2);// 关闭会话2sqlSession2.close();}

当会话1 查询结束并关闭后,我们使用另一个会话执行与会话1 相同的SQL 查询语句,发现并没有发送SQL 语句,因为缓存中已经保存了要查询的数据,这次直接从缓存中获取数据,这就是MyBatis 提供的跨会话级别(SqlSession)的二级缓存机制。

二级缓存相关的设置

1.可以在MyBatis 全局配置文件中的setting标签中配置cacheEnabled属性,表示是否启用二级缓存机制,不过不影响一级缓存。

2.select查询标签中可以设置useCache属性,配置是否使用二级缓存,默认一级缓存是一直生效的。

3.sqlSession.clearCache();方法默认只清除一级缓存中的数据。

4.可以在每个增删改的标签中设置flushCache属性,设置为true后,如果执行了该增删改操作,则一级缓存与二级缓存中的数据都会清空。

二级缓存的缺点

MyBatis 提供的二级缓存机制好像并没有获得开发人员的青睐。原因是二级缓存是一个namespace级别的缓存,如果在不同的namespace下操作同一SQL 语句,可能导致缓存中的数据不正确。在进行多表联查的时候,也可能会导致二级缓存中的数据不正确。所以在实际的开发过程中要慎用二级缓存。(权限名+id 或实现的SQL语句的唯一操作,但是如果是的namespace级别的话会导致的是缓存数据查询不是我们想要的表中的数据。)

Mybatis——缓存原理和分析相关推荐

  1. mybatis缓存原理

    缓存概述 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持: 一级缓存基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 ...

  2. MyBatis 缓存原理解析

    为什么 MyBatis 要缓存 缓存在互联网系统中是非常重要的, 其主要作用是将数据保存到内存中, 当用户查询数据时, 优先从缓存容器中获取数据,而不是频繁地从数据库中查询数据,从而提高查询性能.而在 ...

  3. MyBatis缓存技术(一级缓存、二级缓存)

    MyBatis缓存技术(一级缓存.二级缓存) MyBatis的缓存分类 一级缓存 一级缓存的作用域是一个SqlSession.MyBatis默认开启一级缓存.在同一个SqlSession中,执行相同的 ...

  4. MyBatis 源码分析 - 缓存原理

    1.简介 在 Web 应用中,缓存是必不可少的组件.通常我们都会用 Redis 或 memcached 等缓存中间件,拦截大量奔向数据库的请求,减轻数据库压力.作为一个重要的组件,MyBatis 自然 ...

  5. 实际测试例子+源码分析的方式解剖MyBatis缓存的概念

    前言: 前方高能! 本文内容有点多,通过实际测试例子+源码分析的方式解剖MyBatis缓存的概念,对这方面有兴趣的小伙伴请继续看下去~ 欢迎工作一到五年的Java工程师朋友们加入Java架构开发:79 ...

  6. Mybatis底层原理学习(二):从源码角度分析一次查询操作过程

    在阅读这篇文章之前,建议先阅读一下我之前写的两篇文章,对理解这篇文章很有帮助,特别是Mybatis新手: 写给mybatis小白的入门指南 mybatis底层原理学习(一):SqlSessionFac ...

  7. mybatis 传入id_想深入理解MyBatis架构及原理实例分析 把握这些就够了

    前言 MyBatis是目前非常流行的ORM框架,它的功能很强大,然而其实现却比较简单.优雅.本文主要讲述MyBatis的架构设计思路,并且讨论MyBatis的几个核心部件,然后结合一个select查询 ...

  8. 【深入浅出MyBatis系列十一】缓存源码分析

    为什么80%的码农都做不了架构师?>>>    #0 系列目录# 深入浅出MyBatis系列 [深入浅出MyBatis系列一]MyBatis入门 [深入浅出MyBatis系列二]配置 ...

  9. 五分钟,带你彻底掌握 MyBatis缓存 工作原理

    作者:双子孤狼 blog.csdn.net/zwx900102/article/details/108696005 前言 在计算机的世界中,缓存无处不在,操作系统有操作系统的缓存,数据库也会有数据库的 ...

最新文章

  1. 开发者进阶宝典,HarmonyOS 职业认证全奉上
  2. Oracle 数据库常用操作语句大全
  3. linux 提权一文通
  4. 修改注册表添加信任站点及启用Activex控件(转载)
  5. 重塑APM标杆,博睿数据战略升级助力企业数字化转型
  6. 鸿蒙关键技术研究,鸿蒙内核源码分析(静态链接篇) | 完整小项目看透静态链接过程 | 百篇博客分析HarmonyOS源码 | v54.02...
  7. python调用win32_python调用win32接口进行截图
  8. 【Java基本功】一文读懂final关键字的用法
  9. [独孤九剑]持续集成实践(二)– MSBuild语法入门
  10. js 自动分配金额_深入解析Node.js事件循环工作机制
  11. go-mysql数据-查询--输入数据--实战2
  12. 数据仓库建设 —— 数据质量管理
  13. 在Windows 10 增加和使用英语语音包
  14. java斗地主比大小_斗地主算法的设计与实现–如何比较两手牌的大小
  15. Windows打开文件后提示,文件或目录损坏无法读取。
  16. diskgenius克隆硬盘无法启动_用Diskgenius克隆分区到另一个磁盘上
  17. 深夜更新博客的美女们[组图]
  18. 如何做到长期稳定的禅修?
  19. c# mysql 批量导入_C#:MySql批量数量导入
  20. 保险行业的“偿二代”

热门文章

  1. picoCTF 2022 wp
  2. 数据结构自学笔记二、栈
  3. 最赚钱的十大增值业务
  4. Qt之旅---10 双缓冲绘图
  5. mysql 取前几分钟和几秒,mysql 数据库取前后几秒 几分钟 几小时 几天的语句
  6. python画柱状图怎么规定x轴_Python:Matplotlib 画曲线和柱状图(Code)
  7. jsliang 2020 求职系列
  8. 中山大学计算机在职研究生分数线,中山大学在职研究生的合格分数线不是很高吗...
  9. 强大的矩阵奇异值分解(SVD)及其应用(转)-我们老师推荐的
  10. 请分析计算机测色配色的缺点,测色与配色分析.doc