网易首页 > 网易号 > 正文 申请入驻

图解 | 聊聊 MyBatis 缓存

0
分享至

本文主要内容如下:

一、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 cache = new HashMap();

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

键是 SQL 语句组成的 Key :

Statement Id + Offset + Limmit + Sql + Params

值是 SQL 查询的结果:

2.2 一级缓存配置

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

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 一级缓存总结
  1. MyBatis一级缓存内部设计简单,只是一个没有容量限定的 HashMap,在缓存的功能性上有所欠缺

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

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

三、MyBatis 二级缓存
3.1 MyBatis 二级缓存概述
  1. MyBatis的二级缓存相对于一级缓存来说,实现了SqlSession之间缓存数据的共享,同时粒度更加的细,能够到namespace级别,通过Cache接口实现类不同的组合,对Cache的可控性也更强。

  2. MyBatis在多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用二级缓存的条件比较苛刻。

  3. 在分布式环境下,由于默认的MyBatis Cache实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将 MyBatis的Cache 接口实现,有一定的开发成本,直接使用Redis、Memcached 等分布式缓存可能成本更低,安全性也更高。

3.2 MyBatis 二级缓存原理

一级缓存最大的共享范围就是一个 SqlSession 内部,如果多个 SqlSession 之间需要共享缓存,则需要使用到二级缓存。

开启二级缓存后,会使用 CachingExecutor 装饰 Executor,进入一级缓存的查询流程前,先在CachingExecutor 进行二级缓存的查询。

二级缓存开启后,同一个 namespace下的所有操作语句,都影响着同一个Cache。

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

二级缓存被同一个 namespace 下的多个 SqlSession 共享,是一个全局的变量。MyBatis 的二级缓存不适应用于映射文件中存在多表查询的情况。

通常我们会为每个单表创建单独的映射文件,由于MyBatis的二级缓存是基于namespace的,多表查询语句所在的namspace无法感应到其他namespace中的语句对多表查询中涉及的表进行的修改,引发脏数据问题。

3.3 MyBatis缓存查询的顺序

  1. 先查询二级缓存,因为二级缓存中可能会有其他程序已经查出来的数据,可以拿来直接使用
  2. 如果二级缓存没有命中,再查询一级缓存
  3. 如果一级缓存也没有命中,则查询数据库
  4. SqlSession关闭之后,一级缓存中的数据会写入二级缓存。
3.4 二级缓存配置

开启二级缓存需要在 mybatis-config.xml 中配置:

3.5 二级缓存考题

测试update操作是否会刷新该namespace下的二级缓存。

开启了一级和二级缓存,通过三个SqlSession 查询和更新 学生张三的姓名,判断最后的输出结果是什么?

SqlSession sqlSession1 = factory.openSession(true);
SqlSession sqlSession2 = factory.openSession(true);
SqlSession sqlSession3 = factory.openSession(true);
StudentMapper studentMapper = sqlSession1.getMapper(StudentMapper.class);
StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class);
StudentMapper studentMapper3 = sqlSession3.getMapper(StudentMapper.class); System.out.println("studentMapper读取数据: " + studentMapper.getStudentById(1));
sqlSession1.commit();
System.out.println("studentMapper2读取数据: " + studentMapper2.getStudentById(1)); studentMapper3.updateStudentName("李四",1);
sqlSession3.commit();
System.out.println("studentMapper2读取数据: " + studentMapper2.getStudentById(1));

答案:

张三
张三
李四

解答:三个 SqlSession 是共享 MyBatis 缓存,SqlSession2 更新数据后,MyBatis 的 namespace 缓存(StudentMapper) 就失效了,SqlSession2 最后是从数据库查询到的数据。

四、MyBatis 自定义缓存
4.1 MyBatis 自定义缓存概述

当 MyBatis 二级缓存不能满足要求时,可以使用自定义缓存替换。(较少使用)

自定义缓存需要实现 MyBatis 规定的接口:org.apache.ibatis.cache.Cache。这个接口里面定义了 7 个方法,我们需要自己去实现对应的缓存逻辑。

4.2 整合第三方缓存 EHCache

EHCache 和 MyBatis 已经帮我们整合好了一个自定义缓存,我们可以直接拿来用,不需要自己去实现 MyBatis 的 org.apache.ibatis.cache.Cache 接口。

添加 mybatis-ehcache 依赖包。


org.mybatis.caches
mybatis-ehcache
1.2.1

创建EHCache的配置文件ehcache.xml。


xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">

maxElementsInMemory="1000"
maxElementsOnDisk="10000000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">

设置二级缓存的类型,在xxxMapper.xml文件中设置二级缓存类型

4.3 EHCache配置文件说明

五、总结

本篇分别介绍了 MyBatis 一级缓存、二级缓存、自定义缓存的原理和使用,其中还穿插了 4 道考题来验证 MyBatis 缓存的功能。不足之处是 MyBatis 缓存源码未分析。

参考资料:

https://tech.meituan.com/2018/01/19/mybatis-cache.html

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
解放军中将在京突然去世,两女儿定居美国,亲弟弟关联25家公司

解放军中将在京突然去世,两女儿定居美国,亲弟弟关联25家公司

求实者
2024-06-12 14:30:22
48岁老头娶小10岁大学生,洞房花烛夜,刚爬上床却被女子踹下床

48岁老头娶小10岁大学生,洞房花烛夜,刚爬上床却被女子踹下床

华人星光
2024-06-15 16:14:48
女主播爆料行业内幕,大量女主播都有价格,周淑怡确实值百万

女主播爆料行业内幕,大量女主播都有价格,周淑怡确实值百万

新游戏大妹子
2024-06-14 11:43:32
随着许家印的没落,其女儿的生活也被曝光,奢侈程度令人咋舌

随着许家印的没落,其女儿的生活也被曝光,奢侈程度令人咋舌

天闻地知
2024-06-14 14:07:23
大陆何时会动手?美国官员表态,台湾名嘴:赖清德赌大陆不会攻台

大陆何时会动手?美国官员表态,台湾名嘴:赖清德赌大陆不会攻台

千里持剑
2024-06-15 13:25:04
2023年国家自然科学基金评审专家名单汇总

2023年国家自然科学基金评审专家名单汇总

高分子科学前沿
2024-06-16 07:53:29
中国女排3-2土耳其!赛后评分:张常宁满分+4将出彩,一将需提升

中国女排3-2土耳其!赛后评分:张常宁满分+4将出彩,一将需提升

理工男评篮球
2024-06-15 23:27:43
“坐滩”舰终迎大结局?封锁见效,菲驻军或撤离,中方:允许离开

“坐滩”舰终迎大结局?封锁见效,菲驻军或撤离,中方:允许离开

国学聚焦
2024-06-15 14:41:15
3-0!6000万水货,打脸曼联名宿:西班牙走不远?一眼被看穿?

3-0!6000万水货,打脸曼联名宿:西班牙走不远?一眼被看穿?

贝塔说体育
2024-06-16 05:48:29
开始了!俄罗斯军人亲属呼吁官员儿子顶替亲人

开始了!俄罗斯军人亲属呼吁官员儿子顶替亲人

亡海中的彼岸花
2024-06-15 08:56:51
邢天虎-陕西延长石油(集团)有限责任公司原副董事长

邢天虎-陕西延长石油(集团)有限责任公司原副董事长

开心体育站
2024-06-16 11:19:12
新闻背后:贵州卫健委美女厅官杨慧落马,人上人到鬼中鬼的人生路

新闻背后:贵州卫健委美女厅官杨慧落马,人上人到鬼中鬼的人生路

肖飞说
2024-06-16 01:24:07
22岁小伙雇45岁保姆后,整天不出门在家过二人世界

22岁小伙雇45岁保姆后,整天不出门在家过二人世界

牛城王小帅
2024-06-12 13:48:47
50年石油美元协议到期 沙特:不再续约

50年石油美元协议到期 沙特:不再续约

南方都市报
2024-06-16 07:03:39
广州城中村简直是炼狱

广州城中村简直是炼狱

悠闲葡萄
2024-06-16 14:12:31
某音网红“璇子baby”被认出疑是探花203期中女主?

某音网红“璇子baby”被认出疑是探花203期中女主?

挪威森林
2024-06-16 07:25:21
无人驾驶小车成道路杀手!在后沙峪的交通噩梦

无人驾驶小车成道路杀手!在后沙峪的交通噩梦

悠闲葡萄
2024-06-15 12:43:58
上海这夜,耍大牌周也和勒肉张碧晨,都败给了“全裹”出镜的高叶

上海这夜,耍大牌周也和勒肉张碧晨,都败给了“全裹”出镜的高叶

一娱三分地
2024-06-16 08:55:03
再见曼城!1.2亿标王挂牌出售!顶撞瓜帅,不道歉,或转投大巴黎

再见曼城!1.2亿标王挂牌出售!顶撞瓜帅,不道歉,或转投大巴黎

阿泰希特
2024-06-16 11:34:34
直击:白金汉宫礼台上威廉凯特恩爱对视,夏洛特站C位女王范十足

直击:白金汉宫礼台上威廉凯特恩爱对视,夏洛特站C位女王范十足

文雅笔墨
2024-06-16 01:01:18
2024-06-16 16:10:44
ITPUB学院
ITPUB学院
分享技术干货,了解最新动态
790文章数 627关注度
往期回顾 全部

科技要闻

iPhone 16会杀死大模型APP吗?

头条要闻

"地铁上被诬陷偷拍"男子将直播带货:需面对现实问题

头条要闻

"地铁上被诬陷偷拍"男子将直播带货:需面对现实问题

体育要闻

没人永远年轻 但青春如此无敌还是离谱了些

娱乐要闻

上影节红毯:倪妮好松弛,娜扎吸睛

财经要闻

打断妻子多根肋骨 上市公司创始人被公诉

汽车要闻

售17.68万-21.68万元 极狐阿尔法S5正式上市

态度原创

本地
房产
健康
公开课
军事航空

本地新闻

粽情一夏|海河龙舟赛,竟然成了外国人的大party!

房产要闻

万华对面!海口今年首宗超百亩宅地,重磅挂出!

晚餐不吃or吃七分饱,哪种更减肥?

公开课

近视只是视力差?小心并发症

军事要闻

以军宣布在加沙南部实行"战术暂停"

无障碍浏览 进入关怀版