MyBatis 缓存机制可以提高数据库查询的性能,减少数据库的访问次数。它分为一级缓存和二级缓存。
1. 一级缓存(Local Cache)
特点
-
默认开启,作用范围是 同一个 SqlSession。
-
当查询相同的 SQL 语句并且参数相同时,MyBatis 会直接从缓存中取数据,而不是再次查询数据库。
-
SqlSession 关闭或提交事务后,一级缓存会被清空。
示例
SqlSession sqlSession1 = sqlSessionFactory.openSession();
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
// 第一次查询,数据从数据库获取
User user1 = userMapper1.getUserById(1);
System.out.println(user1);
// 第二次查询,相同 SQL 语句和参数,数据从缓存获取
User user2 = userMapper1.getUserById(1);
System.out.println(user2);
sqlSession1.close(); // 关闭后缓存失效
一级缓存失效情况
-
不同的 SqlSession:MyBatis 的一级缓存是 SqlSession 级别的,不同的 SqlSession 互不影响。
-
执行
sqlSession.commit()
或sqlSession.close()
:事务提交或关闭后,缓存会被清空。 -
执行
sqlSession.clearCache()
:手动清除缓存。 -
执行
update
、insert
或delete
语句:数据被修改后,缓存会失效,以防止脏数据。
2. 二级缓存(Global Cache)
特点
-
需要手动开启,作用范围是 同一个 Mapper(Namespace)。
-
多个 SqlSession 共享 该缓存,提高查询性能。
-
缓存的数据会被序列化,所以返回的对象需要实现
Serializable
接口。 -
缓存默认存储在内存中,也可以集成 Redis、EhCache 等缓存框架。
开启二级缓存
-
在
mybatis-config.xml
中开启全局缓存
<configuration>
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
</configuration>
-
在 Mapper 文件(
UserMapper.xml
)中开启缓存
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="false"/>
-
eviction="LRU"
:缓存淘汰策略,支持LRU
(最近最少使用)、FIFO
(先进先出)、SOFT
(软引用)、WEAK
(弱引用)。 -
flushInterval="60000"
:缓存刷新时间(单位:毫秒)。 -
size="512"
:缓存的最大对象数。 -
readOnly="false"
:是否只读,如果设为true
,所有线程共享数据,不能修改,否则可能会出现并发问题。
-
User
类必须实现Serializable
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String name;
}
二级缓存示例
SqlSession sqlSession1 = sqlSessionFactory.openSession();
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
User user1 = userMapper1.getUserById(1);
sqlSession1.close(); // 关闭 SqlSession,数据进入二级缓存
SqlSession sqlSession2 = sqlSessionFactory.openSession();
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
User user2 = userMapper2.getUserById(1); // 这次查询会从二级缓存获取
sqlSession2.close();
二级缓存失效情况
-
Mapper 没有开启
<cache/>
配置。 -
查询的对象未实现
Serializable
。 -
sqlSession.commit()
或执行update
、insert
、delete
语句后,缓存会被清空。 -
手动调用
sqlSession.clearCache()
。
3. MyBatis 缓存 vs Redis
对比项 | MyBatis 二级缓存 | Redis |
---|---|---|
作用范围 | 当前 Mapper(Namespace) | 跨应用、全局共享 |
存储位置 | JVM 内存 | 独立的 Redis 服务器 |
数据存储 | 对象序列化存储 | key-value 形式存储 |
支持集群 | 不支持 | 支持 |
数据持久化 | 关闭进程后丢失 | 支持持久化 |
适用场景 | 小规模项目 | 分布式、高并发场景 |
推荐方案
-
小型项目:使用 MyBatis 二级缓存即可,提高查询性能。
-
大型项目(分布式、微服务架构):推荐使用 Redis 缓存方案,保证高可用性和扩展性。
4. 整合 MyBatis 和 Redis
如果要用 Redis 作为 MyBatis 的二级缓存,可以使用 mybatis-redis
插件:
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-redis</artifactId>
<version>1.0.0</version>
</dependency>
配置 UserMapper.xml
<cache type="org.mybatis.caches.redis.RedisCache"/>
配置 Redis
在 mybatis-config.xml
添加 Redis 相关配置:
<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
这样,MyBatis 的查询数据就会存储在 Redis 缓存中,提高查询效率。
总结
缓存级别 | 默认开启 | 作用范围 | 清空时机 | 特点 |
---|---|---|---|---|
一级缓存 | ✅ | SqlSession 级别 | SqlSession 关闭、事务提交、执行增删改 | 开销小,自动管理 |
二级缓存 | ❌ | Mapper 级别 | 事务提交、执行增删改、手动清除 | 需要手动开启,可用 Redis |