Mybatis提供了多级缓存机制,能够提高查询性能,减少数据库访问次数。MyBatis 的缓存机制分为 一级缓存 和 二级缓存,每种缓存有不同的使用场景和作用。
一、一级缓存(Local Cache)
一级缓存是 MyBatis 默认启用的缓存,作用范围是 SqlSession(即每次数据库操作都会创建一个新的 SqlSession 实例)。一级缓存是本地缓存,每个 SqlSession 对象都会有一个缓存区域,缓存的内容仅在该 SqlSession 生命周期内有效。
1.工作原理
(1)当执行一次查询时,MyBatis 会将查询结果存入一级缓存中(SqlSession 的内部缓存)。
(2)如果在同一个 SqlSession 内再次执行相同的查询,MyBatis 会直接从缓存中获取结果,而不是重新查询数据库。
(3)由于一级缓存是基于 SqlSession 的,因此当 SqlSession 被关闭时,缓存就会被清空。
2.特点
(1)作用域:仅限当前 SqlSession。
(2)生命周期:在 SqlSession 生命周期内有效,SqlSession 关闭后缓存数据丢失。
(3)失效条件:不同的查询条件会导致缓存失效,也可以通过显式的 clearCache() 方法清除缓存。
3.示例
一级缓存的基本使用
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| String resource = "mybatis-config.xml"; InputStream inputStream = Main.class.getClassLoader().getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); SqlSession sqlSession = sqlSessionFactory.openSession(); // 第一次查询,缓存中没有数据 User user1 = sqlSession.selectOne("com.example.main.test.mapper.UserMapper.selectUser", 1); // 第二次查询相同数据,缓存命中,查询结果直接从缓存获取 User user2 = sqlSession.selectOne("com.example.main.test.mapper.UserMapper.selectUser", 1); sqlSession.close(); // 关闭 SqlSession 后,缓存会被清除 |
二、二级缓存(Global Cache)
二级缓存是跨 SqlSession 的缓存机制,缓存的数据会被存储在内存中,并且可以在多个 SqlSession 中共享。二级缓存是由 MyBatis 负责管理的,因此可以对不同的 Mapper 配置二级缓存。
1.工作原理
开启二级缓存,使得二级缓存在不同的 SqlSession 之间共享。
当执行查询时,如果查询结果不在二级缓存中,MyBatis 会查询数据库并将结果放入二级缓存中,以便后续的 SqlSession 使用。
二级缓存通常存储在 JVM 内存中,可以使用外部缓存框架(如 Ehcache、Redis)来实现缓存存储。
2.特点
作用域:多个 SqlSession 共享。
生命周期:在应用的生命周期内存储缓存数据,直到缓存被显式清除或过期。
需要配置:二级缓存需要在 MyBatis 配置文件中开启并配置。
3.开启二级缓存
(1)基于yml配置
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| spring: # MyBatis mybatis: # Mapper XML 文件的路径 mapper-locations: classpath:mapper/*Mapper.xml # 实体类的路径(扫描相应包下的 POJO 类) type-aliases-package: com.example.main.test.po # 配置 MyBatis 配置文件路径 config-location: classpath:mybatis-config.xml # MyBatis 配置项 configuration: # 启用 MyBatis 二级缓存 cache-enabled: true # 配置日志输出级别(一般为 DEBUG) log-impl: org.apache.ibatis.logging.stdout.StdOutImpl map-underscore-to-camel-case: true # 设置全局的 SQL 执行超时时间(单位:秒) default-statement-timeout: 30 # 执行插入、更新、删除操作时,是否忽略插入时的字段为空值 jdbc-type-for-null: NULL # 开启自动映射 auto-mapping-behavior: FULL |
(2)基于 mybatis-config.xml
启用二级缓存
|---------------------------------------------------------------------------------------------------------------------------------|
| <configuration> <!-- 开启二级缓存 --> <settings> <setting name="cacheEnabled" value="true"/> </settings> </configuration> |
(3)在 Mapper XML 中启用缓存
<cache/>
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| <?xml version="1.0" encoding="UTF-8" ?> <mapper namespace="com.example.main.test.mapper.UserMapper"> <!-- 启用二级缓存 --> <cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/> <!-- 查询、插入、更新、删除等操作 --> <!-- 查询单个用户 --> <select id="selectUser" parameterType="int" resultType="com.example.main.test.po.User"> SELECT * FROM users WHERE id = #{id} </select> </mapper> |
注:
eviction:缓存驱逐策略,支持 LRU(最近最少使用)、FIFO(先进先出)等。
flushInterval:缓存刷新间隔时间,单位是毫秒。
size:缓存的大小,设置最大缓存条目数。
readOnly:是否只读,设置为 true 时,缓存内容不可修改。
4.清除二级缓存
(1)手动清除
通过 <clearCache/> 标签或者 SqlSession.clearCache() 方法清除缓存。
(2)自动清除
执行 insert、update 或 delete 操作时,MyBatis 会自动清除相关的缓存。
5.示例
二级缓存的使用
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| // 第一个 SqlSession 查询,查询结果会被缓存到二级缓存中 SqlSession sqlSession1 = sqlSessionFactory.openSession(); User user1 = sqlSession1.selectOne("com.example.main.test.mapper.UserMapper.selectUser", 1); sqlSession1.close(); // 第一个 SqlSession 关闭,二级缓存保存数据 // 第二个 SqlSession 查询,查询结果会从二级缓存中获取 SqlSession sqlSession2 = sqlSessionFactory.openSession(); User user2 = sqlSession2.selectOne("com.example.main.test.mapper.UserMapper.selectUser", 1); sqlSession2.clearCache(); // 清除缓存 sqlSession2.close(); // 第二个 SqlSession 关闭 |
三、总结
一级缓存:作用于单一 SqlSession,生命周期是 SqlSession 的生命周期。MyBatis 默认启用一级缓存,缓存的内容会在 SqlSession 关闭后失效。
二级缓存:作用于多个 SqlSession,可以在不同的 SqlSession 之间共享数据。需要在 MyBatis 配置和 Mapper 中显式启用。二级缓存可以使用不同的存储实现,例如内存、Ehcache、Redis 等。
MyBatis 的缓存机制通过一级缓存和二级缓存实现了查询结果的高效缓存和复用。一级缓存是基于 SqlSession 的本地缓存,而二级缓存是跨 SqlSession 共享的缓存,适用于大规模的数据复用场景。通过合理配置和使用缓存,可以显著提高数据库查询性能,减少数据库的压力。