首页 > 其他分享 >MyBatis 缓存(一)

MyBatis 缓存(一)

时间:2022-10-21 13:31:07浏览次数:64  
标签:缓存 一级 数据库 查询 SqlSession MyBatis

一、MyBatis 缓存中的常用概念

MyBatis 缓存:它用来优化 SQL 数据库查询的,但是可能会产生脏数据。

SqlSession:代表和数据库的一次会话,向用户提供了操作数据库的方法。

MappedStatement:代表要发往数据库执行的指令,可以理解为是 SQL 的抽象表示。

Executor: 代表用来和数据库交互的执行器,接受 MappedStatment 作为参数。

namespace:每个 Mapper 文件只能配置一个 namespace,用来做 Mapper 文件级别的缓存共享。

映射接口:定义了一个接口,然后里面的接口方法对应要执行 SQL 的操作,具体要执行的 SQL 语句是写在映射文件中。

映射文件:MyBatis 编写的 XML 文件,里面有一个或多个 SQL 语句,不同的语句用来映射不同的接口方法。通常来说,每一张单表都对应着一个映射文件。

二、MyBatis 一级缓存

2.1 一级缓存原理

在一次 SqlSession 中(数据库会话),程序执行多次查询,且查询条件完全相同,多次查询之间程序没有其他增删改操作,则第二次及后面的查询可以从缓存中获取数据,避免走数据库。

每个SqlSession中持有了Executor,每个Executor中有一个LocalCache。当用户发起查询时,MyBatis根据当前执行的语句生成MappedStatement,在Local Cache进行查询,如果缓存命中的话,直接返回结果给用户,如果缓存没有命中的话,查询数据库,结果写入Local Cache,最后返回结果给用户。

Local Cache 其实是一个 hashmap 的结构:

private Map<Object, Object> cache = new HashMap<Object, Object>();

如下图所示,有两个 SqlSession,分别为 SqlSession1 和 SqlSession2,每个 SqlSession 中都有自己的缓存,缓存是 hashmap 结构,存放的键值对。

键是 SQL 语句组成的 Key :

Statement Id + Offset + Limmit + Sql + Params

值是 SQL 查询的结果:

2.2 一级缓存配置

在 mybatis-config.xml 文件配置,name=localCacheScope,value有两种值:SESSIONSTATEMENT

<configuration>
    <settings>
        <setting name="localCacheScope" value="SESSION"/>
    </settings>
<configuration>

SESSION:开启一级缓存功能

STATEMENT:缓存只对当前执行的这一个 SQL 语句有效,也就是没有用到一级缓存功能。

首先我们通过几个考题来体验下 MyBatis 一级缓存。

2.3 一级缓存考题

考题(1)只开启了一级缓存,下面的代码调用了三次查询操作 getStudentById,请判断,下列说法正确的是?

// 打开一个 SqlSession
SqlSession sqlSession = factory.openSession(true);
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class); 
// 根据 id=1 查询学生信息
System.out.println(studentMapper.getStudentById(1)); 
// 根据 id=1 查询学生信息
System.out.println(studentMapper.getStudentById(1)); 
// 根据 id=1 查询学生信息
System.out.println(studentMapper.getStudentById(1));

答案:第一次从数据库查询到的数据,第二次和第二次从 MyBatis 一级缓存查询的数据。

解答:第一次从数据库查询后,后续查询走 MyBatis 一级缓存

考题(2)只开启了一级缓存,下面代码示例中,开启了一个 SqlSession 会话,调用了一次查询,然后对数据进行了更改,又调用了一次查询,下列关于两次查询的说法,正确的是?

// 打开一个 SqlSession
SqlSession sqlSession = factory.openSession(true);
StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class); 
// 根据 id=1 查询学生信息
System.out.println(studentMapper.getStudentById(1)); 
// 插入了一条学生数据,改变了数据库
System.out.println("增加了" + studentMapper.addStudent(buildStudent()) + "个学生"); 
// 根据 id=1 查询学生信息
System.out.println(studentMapper.getStudentById(1)); 
sqlSession.close();

答案:第一次从数据库查询到的数据,第二次从数据库查询的数据

解答:第一次从数据库查询后,后续更新(包括增删改)数据库中的数据后,这条 SQL 语句的缓存失效了,后续查询需要重新从数据库获取数据。

考题(3)当开启了一级缓存,下面的代码中,开启了两个 SqlSession,第一个 SqlSession 查询了两次学生 A 的姓名,第二次 SqlSession 更新了一次学生 A 的姓名,请判断哪个选项符合最后的查询结果。

SqlSession sqlSession1 = factory.openSession(true); 
SqlSession sqlSession2 = factory.openSession(true); 
StudentMapper studentMapper = sqlSession1.getMapper(StudentMapper.class); 
StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class); studentMapper2.updateStudentName("B",1); 
System.out.println(studentMapper.getStudentById(1)); 
System.out.println(studentMapper2.getStudentById(1));

答案

A
B

解答:只开启一级缓存的情况下,SqlSession 级别是不共享的。代码示例中,分别创建了两个 SqlSession,在第一个 SqlSession 中查询学生 A 的姓名,第二个 SqlSession 中修改了学生 A 的姓名为 B,SqlSession2 更新了数据后,不会影响 SqlSession1,所以 SqlSession1 查到的数据还是 A。

2.4 MyBatis 一级缓存失效的场景

  1. 不同的SqlSession对应不同的一级缓存
  2. 同一个SqlSession但是查询条件不同
  3. 同一个SqlSession两次查询期间执行了任何一次增删改操作
  4. 同一个SqlSession两次查询期间手动清空了缓存

2.5 MyBatis 一级缓存总结

  • MyBatis一级缓存内部设计简单,只是一个没有容量限定的 HashMap,在缓存的功能性上有所欠缺

  • MyBatis的一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为Statement

  • 一级缓存的配置中,默认是 SESSION 级别,即在一个MyBatis会话中执行的所有语句,都会共享这一个缓存。

标签:缓存,一级,数据库,查询,SqlSession,MyBatis
From: https://blog.51cto.com/u_15380918/5782531

相关文章

  • 11. MyBatis的缓存
    一、MyBatis的缓存机制  MyBatis在执行DQL(select语句)的时候,将查询结果放到缓存(内存)当中。如果下一次还是执行完全相同的DQL语句,直接从缓存中拿取数据,不再查询数据......
  • Springboot 项目普通类调用 Mapper 接口使用 MybatisPlus 报错:空指针异常(NullPointer
    Springboot项目普通类调用Mapper接口使用MybatisPlus报错:空指针异常(NullPointerException)报错开发时,在普通类调用Mapper接口使用MabatisPlus功能时会报出......
  • Linux清理缓存
     echo1>/proc/sys/vm/drop_caches//1释放页缓存echo2> /proc/sys/vm/drop_caches//2释放dentries和inodes缓存echo3> /proc/sys/vm/drop_caches......
  • MyBatis基础使用二
    MyBatis基础使用二配置Mybatis参考MyBatis基础用法一基本的CRUD接口UserMapperpackagecom.wfy.mapper;importcom.wfy.pojo.User;importorg.apache.ibatis.annota......
  • MyBatis基础使用四
    MyBatis基础使用四动态SQL一、多条件查询语句通过标签进行的多条件查询,通过test属性中的表达式判断标签中的内容是否有效(是否会拼接到sql中)<selectid="SelectCond......
  • SpringBoot+MybatisPlus--文件上传和下载实例
    文件上传时,file是一个临时文件,需要转存到指定位置,否则本次请求完成后临时文件就被删除Controller后台代码:packagecom.itheima.reggie.controller;importcom.itheima......
  • mybatis——下载
    下载地址:https://github.com/mybatis/mybatis-3/releasesmybatis是apache一个开源项目,早期叫做ibatis;Github(github代码管理平台);mybatis:是MyBatisSQLMapperFrameworkf......
  • mybatis使用 Map查询
    //前端传的多选参数List<SemiSerialListVo>semiSerialRecordsList=queryDate.getSemiSerialRecords();/***根据批次号查询备注,组装成map*Map查询的参数map......
  • 开箱即用的数据缓存服务|EMQX Cloud 影子服务应用场景解析
    在物联网业务高速迭代的今天,快速连接物联网设备与平台应用,实现业务快速落地与市场验证,是很多企业塑造核心竞争力、实现业务创新的关键。​​EMQXCloud​​作为一站式运维......
  • Mybatis 插入时设置参数异常: Invalid argument value: java.io.NotSerializableExcept
    记录一个因为同事代码生成造成的问题因为代码中大量的自动生成代码,所以看到LongVARCHAR我也没有过多怀疑  最后定位发现还是自动生成的问题,只是原有的生成代码未使......