MyBatis 是一个流行的 Java 持久层框架,它简化了数据库操作。MyBatis 提供了强大的缓存机制,用于提升性能,减少数据库的访问次数。MyBatis 的缓存机制分为一级缓存和二级缓存。

该图展示了用户通过 SqlSession 发起查询请求,SqlSession 会首先在一级缓存中查找,如果未命中,则在二级缓存中查找,最终返回查询结果的过程。
1. 一级缓存
一级缓存是 MyBatis 的默认缓存,它是 SqlSession 级别的缓存。每个 SqlSession 对象都有自己的一级缓存。查询的结果会存储在当前 SqlSession 中,如果再次执行相同的查询(在同一个 SqlSession 中),MyBatis 会直接从缓存中获取数据,而不再去访问数据库。
一级缓存的特点:
- 作用域:SqlSession 级别,每个 SqlSession 都有自己的缓存。
- 失效条件 :如果调用了
clearCache()
,或者 SqlSession 被关闭,缓存会失效。
示例代码(一级缓存)
xml
<!-- 配置 MyBatis 的 mapper 文件 -->
<mapper namespace="com.example.mapper.UserMapper">
<!-- 查询用户 -->
<select id="getUserById" resultType="com.example.model.User">
SELECT * FROM users WHERE id = #{id}
</select>
</mapper>
java
// 获取 SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
// 第一次查询,MyBatis 会从数据库中获取数据
User user1 = sqlSession.selectOne("com.example.mapper.UserMapper.getUserById", 1);
// 第二次查询,MyBatis 会从一级缓存中获取数据,而不会再去查询数据库
User user2 = sqlSession.selectOne("com.example.mapper.UserMapper.getUserById", 1);
System.out.println(user1 == user2); // 输出 true,表示是同一个对象
sqlSession.close(); // 关闭 SqlSession,缓存清空
2. 二级缓存
二级缓存是跨 SqlSession 共享的缓存。MyBatis 提供了全局共享缓存机制,它的作用范围大于一级缓存,跨越了多个 SqlSession 的生命周期。二级缓存的使用需要手动配置。
二级缓存的特点:
- 作用范围:Mapper 映射器级别,不同的 SqlSession 之间可以共享缓存。
- 缓存实现:默认使用的是内存缓存,也可以使用自定义缓存实现(如 Redis)。
- 失效条件 :如果数据发生变化,比如执行了
update
、insert
或delete
操作,缓存会被清空。
配置二级缓存
在 mybatis-config.xml
文件中,需要启用二级缓存功能,并配置缓存。
xml
<!-- mybatis-config.xml 配置 -->
<configuration>
<settings>
<!-- 启用二级缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>
</configuration>
在 Mapper 配置文件中启用缓存,并配置缓存策略。
xml
<mapper namespace="com.example.mapper.UserMapper">
<!-- 启用二级缓存 -->
<cache/>
<select id="getUserById" resultType="com.example.model.User">
SELECT * FROM users WHERE id = #{id}
</select>
</mapper>
示例代码(二级缓存)
java
// 获取 SqlSession
SqlSession sqlSession1 = sqlSessionFactory.openSession();
SqlSession sqlSession2 = sqlSessionFactory.openSession();
// 第一次查询,MyBatis 会从数据库中获取数据
User user1 = sqlSession1.selectOne("com.example.mapper.UserMapper.getUserById", 1);
sqlSession1.close();
// 第二次查询,跨 SqlSession,数据会从二级缓存中获取
User user2 = sqlSession2.selectOne("com.example.mapper.UserMapper.getUserById", 1);
System.out.println(user1 == user2); // 输出 true,表示是同一个对象(从二级缓存中获取)
sqlSession2.close();
3. 缓存的刷新和清理
MyBatis 提供了多种方式来管理缓存的刷新和清理:
- 手动清理缓存 :可以在代码中调用
clearCache()
方法来清除缓存。 - 执行增删改操作时自动清除缓存 :当执行
insert
、update
、delete
操作时,相关的缓存会被自动清除。
4. 自定义缓存
MyBatis 允许用户实现自定义缓存。例如,可以结合 Redis 来实现分布式缓存,或者使用其他缓存框架。
自定义缓存的示例
xml
<mapper namespace="com.example.mapper.UserMapper">
<!-- 配置自定义缓存 -->
<cache type="com.example.cache.RedisCache"/>
<select id="getUserById" resultType="com.example.model.User">
SELECT * FROM users WHERE id = #{id}
</select>
</mapper>
在 RedisCache
类中,继承 MyBatis 的 Cache
接口,提供对 Redis 的操作。
总结
MyBatis 的缓存机制通过一级缓存和二级缓存大大提高了数据库的访问性能。一级缓存是 SqlSession 级别的缓存,适用于同一 SqlSession 中的重复查询;二级缓存是跨 SqlSession 的共享缓存,可以提升全局的查询效率。通过合理配置和管理缓存,可以优化数据库的访问性能。