MyBatis 缓存机制
MyBatis 缓存机制详解
MyBatis 提供了一种内置的缓存机制,用来提高数据查询的效率。通过缓存,MyBatis 可以减少对数据库的访问,提升系统性能。MyBatis 缓存分为 一级缓存(Local Cache) 和 二级缓存(Global Cache),并且可以与第三方缓存框架集成。
1. MyBatis 缓存简介
- 一级缓存:默认开启,作用范围是会话级别,即同一个 SQLSession 中的查询结果会被缓存。每个 SQLSession 都有自己独立的一级缓存,当 SQLSession 关闭时,一级缓存将被清空。
- 二级缓存:需要手动开启,作用范围是全局级别(Mapper 级别),不同 SQLSession 之间可以共享二级缓存。二级缓存可以减少重复的数据库访问。
MyBatis 缓存机制的基本工作原理是:
- 当执行查询操作时,首先检查缓存中是否存在该查询的结果。
- 如果存在缓存,则直接返回缓存数据。
- 如果缓存中不存在该查询结果,则访问数据库,并将查询结果存入缓存。
2. 一级缓存
一级缓存是 MyBatis 的默认缓存机制,它不需要额外配置,默认情况下是开启的。每个 SQLSession 都会维护一个本地缓存,用来缓存该 SQLSession 中执行的查询结果。
2.1 一级缓存工作原理
- 一级缓存的作用范围是同一个 SQLSession。在同一个 SQLSession 中,执行相同的查询,MyBatis 会从缓存中获取数据,而不会再查询数据库。
- 当执行
insert
、update
、delete
操作时,MyBatis 会清空该 SQLSession 的一级缓存,确保数据的一致性。
2.2 一级缓存示例
public class UserService {
@Autowired
private SqlSession sqlSession;
public void testCache() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 第一次查询,结果会从数据库中获取
User user1 = mapper.getUserById(1);
// 第二次查询相同的记录,结果会从一级缓存中获取,不会再访问数据库
User user2 = mapper.getUserById(1);
}
}
在上述代码中,getUserById
方法被调用两次,第二次查询时 MyBatis 会从一级缓存中获取结果,而不会再访问数据库。
2.3 一级缓存失效条件
一级缓存会在以下情况下失效:
- SQLSession 关闭:当 SQLSession 关闭时,一级缓存也会被清空。
- 执行更新操作:
insert
、update
、delete
等更新操作会清空该会话的一级缓存,确保数据一致性。 - 手动清空缓存:可以通过
sqlSession.clearCache()
手动清空一级缓存。
sqlSession.clearCache(); // 手动清空一级缓存
3. 二级缓存
二级缓存是全局级别的缓存,可以在不同 SQLSession 之间共享。二级缓存的作用范围是Mapper 级别,即同一个 Mapper 中的查询可以被多个 SQLSession 共享。
3.1 二级缓存配置
二级缓存是非默认开启的,需要手动开启。在 MyBatis 中启用二级缓存非常简单,只需要在 Mapper 配置文件或注解中指定开启缓存。
- 在 Mapper XML 中启用二级缓存
在 Mapper XML 文件中,通过添加 <cache>
标签来启用二级缓存:
<mapper namespace="com.example.mapper.UserMapper">
<!-- 启用二级缓存 -->
<cache/>
<select id="getUserById" resultType="User">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
- 通过注解方式启用二级缓存
如果使用注解方式配置 Mapper,可以在接口类上添加 @CacheNamespace
注解来启用二级缓存。
import org.apache.ibatis.annotations.CacheNamespace;
import org.apache.ibatis.annotations.Mapper;
@Mapper
@CacheNamespace
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User getUserById(int id);
}
3.2 二级缓存的工作原理
-
缓存作用范围:二级缓存是 Mapper 级别的缓存,不同 SQLSession 间的查询结果可以共享。
-
缓存存储机制:MyBatis 的二级缓存以对象的序列化方式存储。
-
缓存失效:与一级缓存类似,当执行
insert
、update
、delete
操作时,MyBatis 会清空对应的二级缓存。 -
刷新机制:可以通过
flushInterval
配置自动刷新缓存,单位是毫秒:<cache flushInterval="60000"/> <!-- 60秒刷新一次缓存 -->
3.3 二级缓存示例
public class UserService {
@Autowired
private SqlSessionFactory sqlSessionFactory;
public void testCache() {
// 第一个 SQLSession
SqlSession session1 = sqlSessionFactory.openSession();
UserMapper mapper1 = session1.getMapper(UserMapper.class);
User user1 = mapper1.getUserById(1);
session1.close(); // 一级缓存失效,但查询结果会存入二级缓存
// 第二个 SQLSession
SqlSession session2 = sqlSessionFactory.openSession();
UserMapper mapper2 = session2.getMapper(UserMapper.class);
User user2 = mapper2.getUserById(1); // 从二级缓存中获取
session2.close();
}
}
在上述代码中,session1
执行查询后,结果会存入二级缓存。session2
执行相同的查询时,会从二级缓存中获取数据,而不会再访问数据库。
3.4 配置二级缓存的其他参数
除了 flushInterval
,<cache>
标签还可以配置其他参数,例如:
-
size
:缓存的最大存储对象数目(默认为 1024 个对象)。<cache size="500"/> <!-- 缓存最多存储500个对象 -->
-
readOnly
:是否开启只读模式,默认值为false
。开启只读模式后,缓存中的数据无法修改,提升并发性能。<cache readOnly="true"/>
-
eviction
:缓存的逐出策略,可以设置为LRU
(Least Recently Used, 最近最少使用),FIFO
(先进先出),SOFT
(软引用),WEAK
(弱引用)。默认策略是LRU
。<cache eviction="FIFO"/> <!-- 先进先出策略 -->
4. 与第三方缓存整合
MyBatis 支持与其他第三方缓存框架(如 Ehcache、Redis)集成。通过这种方式,可以进一步增强缓存的功能和性能。
4.1 Ehcache 集成
要集成 Ehcache,首先需要引入 Ehcache 依赖:
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.1.0</version>
</dependency>
然后,在 logback.xml
中指定缓存类型为 Ehcache:
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
最后,配置 Ehcache 的 ehcache.xml
:
<ehcache>
<cache name="com.example.mapper.UserMapper"
maxEntriesLocalHeap="1000"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
overflowToDisk="false"/>
</ehcache>
通过这样的配置,MyBatis 可以利用 Ehcache 提供的强大缓存能力来提升缓存性能和扩展性。
5. 缓存机制的注意事项
- 缓存一致性问题:当数据库中的数据被修改时,一级缓存和二级缓存需要确保同步更新。如果缓存不能及时清除或刷新,可能会导致缓存和数据库数据不一致的问题。MyBatis 默认会在执行
insert
、update
和delete
操作时清空缓存,但在复杂场景下,可能需要手动控制缓存的刷新。 - 缓存的适用场景:MyBatis 的缓存适用于查询频率高、变化较少的场景。例如,用户信息、商品分类等查询频繁但数据更新较少的数据适合使用缓存。而对于频繁更新的数据,不建议使用缓存。
- 缓存的管理:可以通过
sqlSession.clearCache()
手动清除一级缓存,通过@CacheNamespace
或<cache>
标签控制二级
缓存的配置与失效策略。
6. 总结
MyBatis 提供了灵活的一级和二级缓存机制,通过这些缓存机制,可以显著提升查询性能,减少数据库的压力。一级缓存是默认开启的会话级缓存,适用于单次会话中的重复查询。而二级缓存是全局共享的缓存,适合用于查询频率高且数据变化较少的场景。
此外,MyBatis 还支持与 Ehcache、Redis 等第三方缓存框架集成,从而提供更加强大的缓存管理功能。开发者在使用缓存时,应根据实际业务需求灵活配置缓存策略,避免缓存一致性问题。