MyBatis⑧缓存
MyBatis⑧缓存
13、缓存
13.1、简介
缓存(Cache)是存在内存中的临时数据。
- 为什么使用缓存?
- 用户在查询数据时不用从磁盘上查询,而是从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题;
- 减少和数据库的交互次数,减少系统开销,提高系统效率。
- 使用缓存
- 经常查询且不经常改变的数据,可使用缓存;
- 不经常查询或经常改变的数据,不使用缓存。
MyBatis包含一个强大的事务性查询缓存机制,易于配置和使用。
13.2、一级缓存
1、说明
一级缓存也叫会话缓存。
- 默认情况下,只启用了本地的一级缓存;
- 仅对一个会话中的数据进行缓存,即缓存只在一个SqlSession从获取到关闭这个区间有效;
- 增删改操作会刷新缓存;
2、Mapper
/**
* 根据ID获取用户
* @param id 用户ID
* @return 用户
*/
User getUserById(int id);
<select id="getUserById" resultType="user">
select *
from mybatis.user
where id = #{id}
</select>
3、测试
进行以下3种测试:
- 同一会话中,查询相同数据;
- 同一会话中,查询不同数据;
- 不同会话中,查询相同数据。
同一会话中,查询相同数据
@Test
public void tesGetUserById() {
// 获取SqlSession
SqlSession sqlSession = MyBatisUtils.getSqlSession();
// 获取Mapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 执行方法
User user = mapper.getUserById(1);
User user1 = mapper.getUserById(1);
System.out.println("-----------");
System.out.println(user);
System.out.println("-----------");
System.out.println(user1);
System.out.println("-----------");
System.out.println(user == user1);
System.out.println("-----------");
// 关闭连接
sqlSession.close();
}
测试结果:在第一次查询的时候执行了SQL语句;第二次查询相同数据时,直接读取缓存。

同一会话中,查询不同数据
// 执行方法
User user = mapper.getUserById(1);
User user1 = mapper.getUserById(2);
System.out.println("-----------");
System.out.println(user);
System.out.println("-----------");
System.out.println(user1);
System.out.println("-----------");
System.out.println(user == user1);
System.out.println("-----------");
测试结果:在第一次查询的时候执行了SQL语句;第二次查询不同数据时,又执行了SQL语句。

不同会话中,查询相同数据。
@Test
public void tesGetUserById() {
// 获取SqlSession会话
SqlSession sqlSession = MyBatisUtils.getSqlSession();
// 获取Mapper
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 执行方法
User user = mapper.getUserById(1);
System.out.println(user);
// 关闭连接
sqlSession.close();
// --------------------------------
// 获取另一个SqlSession会话
SqlSession sqlSession1 = MyBatisUtils.getSqlSession();
// 获取Mapper
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
// 执行方法
User user1 = mapper1.getUserById(1);
System.out.println(user1);
// 关闭连接
sqlSession1.close();
}
测试结果:
-
在第一个会话中查询的时候执行了SQL语句;
-
第二次会话中查询的时候没有读取缓存,又执行了SQL语句。

4、注意
-
select 语句的结果将会被缓存。
-
insert、update 和 delete 语句会刷新缓存,此时再查询之前查过的结果也需要重新执行SQL。
![]()
-
手动清理缓存
sqlSession.clearCache();
13.3、二级缓存
1、说明
二级缓存也叫全局缓存。
- 基于
namespace级别的缓存,即一个Mapper中有效; - 需要在
Mapper.xml中手动开启:<cache/>,就可以达成以下效果:select语句的结果将会被缓存;insert、update和delete语句会刷新缓存;- 使用LRU算法(
Least Recently Used)来清除不需要的缓存; - 缓存不会定时进行刷新(即没有刷新间隔)。
- 缓存会保存1024 个列表或对象的引用 。
- 缓存会被视为读/写缓存,即获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
- 工作机制:
- 一个会话中查询的数据,会放在一级缓存中;
- 会话关闭,一级缓存失效,其中的数据被保存到二级缓存中;
- 开启新的会话,先读取二级缓存,再读取当前会话的一级缓存;
- 不同Mapper的数据存放在各自的缓存中。
2、使用
开启设置

全局缓存开启的默认值为true。为了提高可读性,如果要使用二级缓存,要显式地在核心配置文件中开启。
<setting name="cacheEnabled" value="true"/>
使用二级缓存
注意:开启二级缓存之前,涉及到的实体类要实现可序列化接口Serializable。
在要使用二级缓存的Mapper.xml中使用cache标签。
<!-- 使用默认的二级缓存 -->
<cache/>
也可以自定义缓存配置
<!-- 使用自定义配置的二级缓存 -->
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
测试结果:
-
未开启二级缓存:
- 两个会话的查询结果存储在各自的会话中,无法共享,都需要执行SQL语句。
![]()
测试:
-
第一条查询语句:先后读取二级缓存和一级缓存都没有相应数据,执行SQL并将结果保存到一级缓存。会话结束后,一级缓存失效,其内容保存到二级缓存。
-
第二条查询语句:读取二级缓存获取数据,无需执行SQL。
![]()
13.4、小结
- 一级缓存也叫会话缓存,在一个会话中有效;
- 二级缓存也叫全局缓存,在一个Mapper中有效;
- 默认情况下,一级缓存开启,二级缓存关闭;
- 当一次会话结束时,一级缓存失效,其中的数据保存到二级缓存中;
- 用户查数据的顺序:先读取二级缓存,再读取一级缓存,再访问数据库。
- 增删改操作都会刷新缓存。
13.4、Ehcache
可以更完善地自定义缓存配置。
-
导包
<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache --> <dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.2.1</version> </dependency> -
编写ehcache配置文件
<?xml version="1.0" encoding="UTF-8" ?> <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false"> <diskStore path="./tmpdir/Tmp_EhCache"/> <defaultCache eternal="false" maxElementsInMemory="10000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="1800" timeToLiveSeconds="259200" memoryStoreEvictionPolicy="LRU"/> <cache name="cloud_user" eternal="false" maxElementsInMemory="5000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="1800" timeToLiveSeconds="1800" memoryStoreEvictionPolicy="LRU"/> </ehcache> -
使用Ehcache缓存
<!-- 使用Ehcache缓存 --> <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
标签: MyBatis




浙公网安备 33010602011771号