10.5 MyBatis缓存机制
在实际项目开发中,通常对数据库査询的性能要求很高,而MyBatis
提供了查询缓存来缓存数据,从而达到提高查询性能的要求。MyBatis
的查询缓存分为一级缓存和二级缓存。
- 一级缓存是
SqlSession
级别的缓存, - 二级缓存是
mapper
级别的缓存,二级缓存是多个Sqlsession
共享的。
MyBatis
通过缓存机制减轻数据压力,提高数据库性能。
10.5.1一级缓存(SqlSession级别)
MyBatis
的一级缓存是Sqlsession
级别的缓存。在操作数据库时需要构造SqlSession
对象,在SqlSession
对象中有一个HashMap
用于存储缓存数据。不同的SqlSession
之间的缓存数据区域(HashMap
)是互相不影响的。
一级缓存的作用域是SqlSession
范围的,当在同一个SqlSession
中执行两次相同的SQL语句时,
- 第一次执行完毕会将从数据库中査询的数据写到缓存(内存),
- 第二次査询时会从缓存中获取数据,不再去底层数据库查询,从而提高查询效率。
需要注意的是,如果SqlSession
执行了DML
操作(insert
、update
和delete
),并提交到数据库,MyBatis
则会清空SqlSession
中的一级缓存,这样做的目的是为了保证缓存中存储的是最新的信息,避免出现脏读现象。
当一个SqlSession
结束后该SqlSession
中的一级缓存也就不存在了。Mybatis
默认开启一级缓存,不需要进行任何配置。
缓存机制
MyBatis
的缓存机制是基于id
进行缓存的,也就是说,MyBatis
使用HashMap
缓存数据时,是使用对象的id
作为key
,对象作为vaue
保存的.
示例: OneLevelCacheTest
接下来我们测试MyBatis
的一级缓存.
环境搭建
创建并初始化数据库表
1 | # 创建数据库表 |
创建持久化对象
1 | package domain; |
工具类
1 | public class SqlSessionFratoryTools { |
Mapper.xml映射文件
1 |
|
Mapper接口
1 | package mapper; |
测试从一级缓存中查询数据
1 | package test; |
1 | DEBUG [main] ==> Preparing: select * from tb_user where id=? |
仔细观察MyBatis
的执行结果,在第一次查询id
为1
的User
对象时执行了一条select
语句,但是第二次获取id
为1
的User
对象时并没有执行select
语句。
因为此时一级缓存也就是SqlSession
缓存中已经缓存了id
为1
的User
对象,MyBatis
直接从缓存中将对象取出来,并没有再次去数据库查询,所以第二次没有再执行select
语句。
执行DML语句时会自动清空缓存
1 | package test; |
运行结果:
1 | DEBUG [main] ==> Preparing: select * from tb_user where id=? |
仔细观察MyBatis
的执行结果,在第一次查询id
为1
的User
对象时执行了一条select
语句,接下来执行了一个delete
操作,MyBatis
为了保证缓存中存储的是最新的信息会清空Sqlsession
缓存。
当第二次获取id
为1
的User
对象时.一级缓存也就是Sqlsession
缓存中并没有缓存任何对象,所以MyBatis
再次执行select
语句去查询id
为1
的User
对象。
如果注释delete操作的代码:
1 | // userMapper.deleteUserById(5); |
由于并没有执行DML
操作并将操作提交到数据库,故此时MyBatis
不会清空SqlSession
缓存,当再次查询id
为1
的User
对象时不会执行select
语句。
此时运行效果如下:
1 | DEBUG [main] ==> Preparing: select * from tb_user where id=? |
调用SqlSession的clearCache方法手动清除一级缓存
1 | package test; |
运行效果如下:
1 | DEBUG [main] ==> Preparing: select * from tb_user where id=? |
仔细观察MyBatis
的执行结果,在第一次查询id
为1
的User
对象时执行了一条select
语句,接下来调用SqlSession
的clearCache()
方法,该方法会清空SqlSession
缓存。当第二次获取id
为1
的User
对象时,一级缓存中并没有缓存任何对象,所以MyBatis
再次执行select
语句去查询id
为1
的User
对象。
关闭SqlSession时缓存会被清空
1 | package test; |
运行结果:
1 | DEBUG [main] ==> Preparing: select * from tb_user where id=? |
仔细观察MyBatis
的执行结果,在第一次查询id
为1
的User
对象时执行了一条select
语句,接下来调用Sqlsession
的close()
方法,该方法会关闭SqlSession
缓存。当第二次获取id
为1
的User
对象时一级缓存也就是SqlSession
缓存是一个全新的对象,一级缓存中并没有缓存任何对象,所以MyBatis
再次执行select
语句去查询id
为1
的User
对象。