首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >mybatis缓存详解

mybatis缓存详解

作者头像
一只牛博
发布2025-05-30 14:27:36
发布2025-05-30 14:27:36
23300
代码可运行
举报
运行总次数:0
代码可运行

mybatis的缓存

mybatis的一级缓存是Session级别的缓存。一级缓存的作用域默认是一个SqlSession。Mybatis默认开启一级缓存。

在同一个SqlSession中,执行相同的查询SQL,第一次会去数据库进行查询,并把对象放入缓存中,第二次以后是直接去缓存中取。当执行SQL查询中间发生了事务提交的操作,都会把当前SqlSession的缓存清空。

两条SQL的下列五个值相同,即可以认为是相同的SQL。

代码语言:javascript
代码运行次数:0
运行
复制
StatementId+Offset+Limit+Sql+Params
代码语言:javascript
代码运行次数:0
运行
复制
CacheKey cacheKey = new CacheKey();
//MappedStatement的id
// id 就是Sql语句的所在位置 包名 + 类名 + SQL名称
cacheKey.update(ms.getId());
// offset 就是 0
cacheKey.update(rowBounds.getOffset());
// limit 就是 Integer.MAXVALUE
cacheKey.update(rowBounds.getLimit());
// 具体的SQL语句
cacheKey.update(boundSql.getSql());
//后面是update了sql中带的参数
cacheKey.update(value);
...

如果以上的sqlSession与sql都是同一个,那么在第二次查询的时候就会是一级缓存,而不是执行数据库查询

具体的实现如下

代码语言:javascript
代码运行次数:0
运行
复制
@Test
//	@Transactional
	public void testMybatis2(){
		SqlSession sqlSession = factory.openSession();
		SysQuartzJobLogMapper sysQuartzJobLogMapper1 = sqlSession.getMapper(SysQuartzJobLogMapper.class);
		SysQuartzJobLogMapper sysQuartzJobLogMapper2 = sqlSession.getMapper(SysQuartzJobLogMapper.class);

		List<Map<String, Object>> jobLogsById = sysQuartzJobLogMapper1.getJobLogsById(new Page<>(1, 10), "23dedbb5-af24-11ec-a42d-0894ef72d9c4");
		System.out.println(jobLogsById.size() + "==>" + jobLogsById);
		/*try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}*/
		List<Map<String, Object>> jobLogsById2 = sysQuartzJobLogMapper2.getJobLogsById(new Page<>(1, 10), "23dedbb5-af24-11ec-a42d-0894ef72d9c4");
		System.out.println(jobLogsById2.size() + "==>" + jobLogsById2);
	}
image-20220409123130647
image-20220409123130647

注意⚠️:从截图中可以看出来,打印sql执行只打印了一次,而第二次直接输出结果,说明是直接从缓存中查出来的,这里还需要注意的是使用的sqlSeeion来获取的相关mapper。

如果使用的是springbean的方式来获取mapper

代码语言:javascript
代码运行次数:0
运行
复制
@Test
//	@Transactional
	public void testMybatis2(){
		/*SqlSession sqlSession = factory.openSession();
		SysQuartzJobLogMapper sysQuartzJobLogMapper1 = sqlSession.getMapper(SysQuartzJobLogMapper.class);
		SysQuartzJobLogMapper sysQuartzJobLogMapper2 = sqlSession.getMapper(SysQuartzJobLogMapper.class);*/

		List<Map<String, Object>> jobLogsById = sysQuartzJobLogMapper.getJobLogsById(new Page<>(1, 10), "23dedbb5-af24-11ec-a42d-0894ef72d9c4");
		System.out.println(jobLogsById.size() + "==>" + jobLogsById);
		/*try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}*/
		List<Map<String, Object>> jobLogsById2 = sysQuartzJobLogMapper.getJobLogsById(new Page<>(1, 10), "23dedbb5-af24-11ec-a42d-0894ef72d9c4");
		System.out.println(jobLogsById2.size() + "==>" + jobLogsById2);
image-20220409124143863
image-20220409124143863

注意⚠️:可以从执行结果来看,这里其实用到的是同一个sql,导致mybatis一级缓存失效的原因是两个SqlSession,可以发现这里是创建了两个SqlSession。

然后如果在这个测试类上加入@Transactional注解的时候发现他又可以使用一级缓存了。

原因分析

结论:Spring将MyBatis的DefaultSqlSession类替换成了SqlSessionTemplate。 MyBatis的一级缓存是基于SqlSession来实现的,对应MyBatis中sqlSession接口的默认实现类是DefaultSqlSession,如果执行的SQL相同时,并且使用的是同一个SqlSession对象,那么就会触发对应的缓存机制。 但是在Spring整合MyBatis后,Spring使用MyBatis不再是直接调用MyBatis中的信息,而是通过调用调用mybatis-spring.jar中的类,继而达到间接调用MyBatis的效果。但在mybatis-spring.jar中,引入了一个SqlSessionTemplate类,它和Spring的事务管理器共同配合,创建对应的SqlSession连接。 即在没有添加@Transactional注解的情况下,每调用一次查询SQL,就会通过SqlSessionTemplate去创建sqlSession,即相当于新创建一次连接,故而每次查询在调试结果看来就是一级缓存失效。

除此之外如果是在mysql中操作删除或者更新数据,那么就会造成两次获取到的数据不一致

并且在我看来这个一级缓存是没什么意义的,因为一般不会在同一个方法中会调用某个方法两次。

mybatis的二级缓存,针对的是mapper,或者也可以说是sqlFactory

首先说一下他的配置

在配置文件中加入这句话

代码语言:javascript
代码运行次数:0
运行
复制
mybatis-plus.configuration.cache-enabled=true

然后在你想要开启二级缓存的mapper中加入

代码语言:javascript
代码运行次数:0
运行
复制
	<cache/>
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-05-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • mybatis的缓存
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档