dnf手游oppo客户端
1.71 GB · 2025-11-12
SESSION 或 STATEMENT)。commit()、close()、rollback() 方法,该 SqlSession 的一级缓存会被清空。这是为了防止读取到脏数据。// 假设获取的 SqlSession 和 UserMapper
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
// 第一次查询,会发送 SQL 到数据库
User user1 = mapper.selectUserById(1L);
System.out.println(user1);
// 第二次查询,SQL 和参数完全相同,直接从一级缓存返回,不查询数据库
User user2 = mapper.selectUserById(1L);
System.out.println(user2);
// 判断是否为同一个对象(是,因为从缓存中返回的是同一个对象的引用)
System.out.println(user1 == user2); // 输出:true
// 执行一个更新操作
mapper.updateUser(user1);
// 此时,一级缓存被清空
// 第三次查询,因为缓存被清空,会再次发送 SQL 到数据库
User user3 = mapper.selectUserById(1L);
System.out.println(user3 == user1); // 输出:false (虽然是同一条数据,但已是新对象)
}
a. 全局配置文件 ( mybatis-config.xml ) :
必须显式设置开启二级缓存(虽然默认是 true,但显式声明是个好习惯)。
<configuration>
<settings>
<!-- 开启全局二级缓存,默认就是 true,但建议写明 -->
<setting name="cacheEnabled" value="true"/>
</settings>
</configuration>
b. Mapper XML 文件:
在需要开启二级缓存的 Mapper.xml 中添加 <cache/> 标签。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.UserMapper">
<!-- 开启本 Mapper 的二级缓存 -->
<cache
eviction="FIFO"
flushInterval="60000"
size="512"
readOnly="true"/>
<!-- 其他 SQL 定义 -->
<select id="selectUserById" parameterType="long" resultType="User" useCache="true">
SELECT * FROM user WHERE id = #{id}
</select>
</mapper>
<cache/> 标签属性:
eviction:缓存回收策略。
LRU(默认):最近最少使用。FIFO:先进先出。SOFT:软引用,基于垃圾回收器状态和软引用规则移除。WEAK:弱引用,更积极地移除。flushInterval:缓存刷新间隔(毫秒),默认不清空。
size:缓存存放多少元素。
readOnly:是否为只读。
true:返回相同的缓存对象实例,性能好,但不允许修改。false(默认):通过序列化返回缓存对象的拷贝,安全,性能稍差。commit() 后,会清空 整个对应 Mapper 的二级缓存,以保证数据一致性。// 第一个 SqlSession
try (SqlSession sqlSession1 = sqlSessionFactory.openSession()) {
UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
User user1 = mapper1.selectUserById(1L); // 查询数据库
sqlSession1.close(); // 关闭时,数据存入二级缓存
}
// 第二个 SqlSession(与第一个不同)
try (SqlSession sqlSession2 = sqlSessionFactory.openSession()) {
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
// 查询相同的 SQL,直接从二级缓存获取,不查询数据库
User user2 = mapper2.selectUserById(1L);
}
// 第三个 SqlSession,执行了更新
try (SqlSession sqlSession3 = sqlSessionFactory.openSession()) {
UserMapper mapper3 = sqlSession3.getMapper(UserMapper.class);
User user = mapper3.selectUserById(1L);
user.setName("New Name");
mapper3.updateUser(user); // 执行更新
sqlSession3.commit(); // 提交时,清空 UserMapper 的二级缓存
}
// 第四个 SqlSession
try (SqlSession sqlSession4 = sqlSessionFactory.openSession()) {
UserMapper mapper4 = sqlSession4.getMapper(UserMapper.class);
// 因为缓存已被清空,所以会再次查询数据库
User user4 = mapper4.selectUserById(1L);
}
readOnly="false",那么对应的实体类必须实现 Serializable 接口。commit() 或 close() 时,数据才会从一级缓存转存到二级缓存。<cache-ref> 让多个 Mapper 共享一个缓存,但不推荐,容易引起数据混乱。当发起一个查询请求时,MyBatis 的缓存查询顺序是:
查询到的数据会 先存入一级缓存,在 SqlSession 关闭或提交时,再转存到二级缓存。
| 特性 | 一级缓存 | 二级缓存 |
| 作用域 | SqlSession | Mapper (Namespace) |
| 默认状态 | 开启 | 关闭 |
| 是否共享 | 否,Session 独享 | 是,跨 Session 共享 |
| 清空时机 | UPDATE/INSERT/DELETE, commit(), close() | 同 Mapper 的 UPDATE/INSERT/DELETE + commit() |