MyBatis 确实内置了缓存功能,但默认的开启情况取决于缓存级别:
一级缓存(本地缓存)
默认状态:自动开启(无法全局关闭)
范围:SqlSession 级别(同一个 SqlSession 内有效)
特性:
同一个 SqlSession 中相同的查询会直接从缓存返回结果
执行 INSERT/UPDATE/DELETE 或调用 clearCache() 会清空缓存
事务提交或回滚也会清空缓存
二级缓存(全局缓存)
默认状态:关闭,需要手动配置开启
范围:Mapper 命名空间级别(跨 SqlSession 共享)
开启方式:
<!-- 在 mybatis-config.xml 中 -->
<settings><setting name="cacheEnabled" value="true"/> <!-- 默认就是 true -->
</settings><!-- 在具体 Mapper.xml 中 -->
<mapper namespace="..."><cache/> <!-- 显式声明才启用二级缓存 -->
</mapper>
缓存验证方法
验证一级缓存:
// 第一次查询(访问数据库)
User user1 = sqlSession.selectOne("getUser", 1);
// 第二次相同查询(从一级缓存获取)
User user2 = sqlSession.selectOne("getUser", 1);
System.out.println(user1 == user2); // 输出 true 表示缓存生效
验证二级缓存:
// 第一个 SqlSession
User user1 = sqlSession1.selectOne("getUser", 1);
sqlSession1.close(); // 必须关闭才会存入二级缓存// 第二个 SqlSession
User user2 = sqlSession2.selectOne("getUser", 1);
System.out.println(user1 == user2); // 输出 false(不是同一对象)
// 但实际不会访问数据库(查看日志确认)
缓存问题排查
如果遇到查询结果与数据库不一致:
检查是否开启了二级缓存(查看 Mapper.xml)
在查询方法上添加 flushCache 属性临时禁用缓存:
<select id="getUser" resultType="User" flushCache="true">SELECT * FROM user WHERE id = #{id}
</select>
查看 MyBatis 执行日志确认是否真正访问了数据库
注意:在读写分离或多数据源环境下,缓存可能导致更复杂的一致性问题,需要特别注意。