11. MyBatis的一级缓存和二级缓存有什么区别?如何配置和使用二级缓存?
在 MyBatis 中,缓存机制用于减少数据库访问次数,提高应用程序性能。MyBatis 提供了两级缓存:一级缓存和二级缓存。
1. 一级缓存(Local Cache)
-
作用范围:一级缓存作用于
SqlSession级别。即在同一个SqlSession中执行相同的 SQL 查询,如果查询参数相同,MyBatis 会从缓存中直接返回结果,而不会再次查询数据库。 -
默认开启:一级缓存是默认开启的,并且无法关闭。
-
缓存生命周期:一级缓存的生命周期与
SqlSession的生命周期一致。当SqlSession关闭后,一级缓存也随之被清空。 -
失效条件:在
SqlSession期间,如果执行了INSERT、UPDATE、DELETE等写操作,一级缓存将被清空,确保数据一致性。
示例:
-
SqlSession session = sqlSessionFactory.openSession();
-
User user1 = session.selectOne("selectUserById", 1);
-
User user2 = session.selectOne("selectUserById", 1); // 第二次查询将从缓存中获取结果
在这个例子中,如果在同一个 SqlSession 中两次查询相同的 User 对象,第二次查询结果将从一级缓存中获取。
2. 二级缓存(Global Cache)
-
作用范围:二级缓存作用于
Mapper映射器级别。即同一个Mapper中执行相同的 SQL 查询,如果查询参数相同,MyBatis 会从二级缓存中直接返回结果,而不会再次查询数据库。 -
手动配置:二级缓存默认是关闭的,需要显式配置才能开启。
-
缓存共享:二级缓存是跨
SqlSession的,因此不同的SqlSession实例可以共享同一个二级缓存。 -
失效条件:在某个
Mapper中执行了INSERT、UPDATE、DELETE操作,二级缓存将被清空,确保数据一致性。
示例:
-
// 第一次查询,结果会存入二级缓存
-
try (SqlSession session1 = sqlSessionFactory.openSession()) {
-
UserMapper mapper = session1.getMapper(UserMapper.class);
-
User user1 = mapper.selectUserById(1);
-
}
-
-
// 第二次查询,不同的 SqlSession 实例,结果从二级缓存中获取
-
try (SqlSession session2 = sqlSessionFactory.openSession()) {
-
UserMapper mapper = session2.getMapper(UserMapper.class);
-
User user2 = mapper.selectUserById(1);
-
}
在这个例子中,即使在不同的 SqlSession 实例中,第二次查询的结果也可以从二级缓存中获取。
如何配置和使用二级缓存?
要使用 MyBatis 的二级缓存,需要进行以下配置:
1. 启用全局二级缓存
在 MyBatis 的全局配置文件(如 mybatis-config.xml)中,启用全局二级缓存支持:
-
<settings>
-
<setting name="cacheEnabled" value="true"/>
-
</settings>
默认情况下,cacheEnabled 设置为 true,表示全局启用二级缓存。
2. 在 Mapper 文件中启用二级缓存
在具体的 Mapper 文件中,通过 <cache> 标签为某个映射器启用二级缓存:
-
<mapper namespace="com.example.mapper.UserMapper">
-
-
<!-- 启用二级缓存 -->
-
<cache />
-
-
<!-- SQL 映射语句 -->
-
<select id="selectUserById" resultType="User">
-
SELECT * FROM user WHERE id = #{id}
-
</select>
-
-
</mapper>
<cache> 标签默认配置了 LRU(Least Recently Used,最近最少使用)缓存策略、无超时清除、无缓存大小限制等默认参数。
3. 配置二级缓存的行为
你可以在 <cache> 标签中配置缓存的具体行为,如缓存策略、缓存大小、过期时间等。
常见配置选项:
-
eviction:缓存回收策略,默认为LRU(最近最少使用),其他选项包括FIFO(先进先出)、SOFT(软引用)、WEAK(弱引用)。 -
flushInterval:缓存刷新间隔,默认情况下不会自动刷新,可以设置毫秒级的刷新间隔。 -
size:缓存的数量,默认没有限制。 -
readOnly:是否只读,默认为false,如果设置为true,则提高并发性能,但所有返回的对象在缓存期间不可修改。
示例配置:
-
<cache
-
eviction="FIFO"
-
flushInterval="60000" <!-- 60秒刷新一次 -->
-
size="512" <!-- 缓存最多保存 512 个对象 -->
-
readOnly="true" <!-- 只读缓存,提升并发性能 -->
-
/>
4. 使用二级缓存的注意事项
-
与事务管理的关系:二级缓存与事务紧密关联。只有在事务提交后,查询结果才会被存储到二级缓存中。如果事务未提交或回滚,则缓存不会更新。
-
序列化:MyBatis 的二级缓存需要将缓存对象序列化,因此被缓存的对象必须实现
Serializable接口。 -
缓存失效:如前所述,当执行插入、更新或删除操作时,二级缓存会被清空,以确保数据一致性。
5. 二级缓存的使用示例
假设你有以下 Java 类和 Mapper 接口:
-
public class User implements Serializable {
-
private int id;
-
private String name;
-
// Getters and setters
-
}
-
-
public interface UserMapper {
-
User selectUserById(int id);
-
}
MyBatis 配置文件:
-
<settings>
-
<setting name="cacheEnabled" value="true"/>
-
</settings>
UserMapper.xml:
-
<mapper namespace="com.example.mapper.UserMapper">
-
<cache />
-
<select id="selectUserById" resultType="User">
-
SELECT * FROM user WHERE id = #{id}
-
</select>
-
</mapper>
在启用了二级缓存之后,第一次查询时 MyBatis 会从数据库中获取数据并存储到二级缓存中。第二次查询相同的数据时,MyBatis 会直接从二级缓存中获取结果,而不再访问数据库。
总结
-
一级缓存:作用于
SqlSession级别,默认开启,生命周期与SqlSession相同,主要用于减少同一个会话中重复查询的数据库访问。 -
二级缓存:作用于
Mapper级别,默认关闭,需要手动配置。二级缓存是跨SqlSession的缓存,适合在多个会话中共享查询结果。
通过合理配置和使用二级缓存,可以显著提高 MyBatis 应用的性能,特别是在读多写少的场景中,二级缓存能够有效减少数据库的压力,提高查询效率。

浙公网安备 33010602011771号