java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > mybatis 缓存机制

Mybatis中的缓存机制解析

作者:程序员小假

这篇文章给大家介绍mybatis中的缓存机制,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧

核心概览

一级缓存

1. 作用域

2. 工作机制

  1. 第一次执行查询后,查询结果会被存储到 SqlSession 关联的一级缓存中。
  2. 在同一个 SqlSession 中,再次执行 完全相同的 SQL 查询(包括语句和参数)时,会直接返回缓存中的对象,而不会去数据库查询。
  3. 如果 SqlSession 执行了 增(INSERT)、删(DELETE)、改(UPDATE) 操作,或者调用了 commit()close()rollback() 方法,该 SqlSession 的一级缓存会被清空。这是为了防止读取到脏数据。

3. 示例说明

// 假设获取的 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 (虽然是同一条数据,但已是新对象)
}

4. 注意事项

二级缓存

1. 作用域

2. 开启与配置

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>

3. 工作机制

  1. 当一个 SqlSession 执行查询后,在关闭或提交时,其查询结果会被存入二级缓存。
  2. 另一个 SqlSession 执行相同的查询时,会先从二级缓存中查找数据。如果找到,则直接返回,否则再去数据库查询。
  3. 任何一个 SqlSession 执行了 增、删、改 操作并 commit() 后,会清空 整个对应 Mapper 的二级缓存,以保证数据一致性。

4. 示例说明

// 第一个 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);
}

5. 注意事项

缓存顺序与总结

当发起一个查询请求时,MyBatis 的缓存查询顺序是:

  1. 先查二级缓存:查看当前 Mapper 的二级缓存中是否有数据。
  2. 再查一级缓存:如果二级缓存没有,再查看当前 SqlSession 的一级缓存中是否有数据。
  3. 最后查数据库:如果两级缓存都没有,才发送 SQL 语句到数据库执行查询。

查询到的数据会 先存入一级缓存,在 SqlSession 关闭或提交时,再转存到二级缓存

特性

一级缓存

二级缓存

作用域

SqlSession

Mapper (Namespace)

默认状态

开启

关闭

是否共享

否,Session 独享

是,跨 Session 共享

清空时机

UPDATE/INSERT/DELETE, commit(), close()

同 Mapper 的 UPDATE/INSERT/DELETE + commit()

使用建议

到此这篇关于Mybatis 的缓存机制的文章就介绍到这了,更多相关mybatis 缓存机制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文