mybatis的缓存机制

发布于:2024-10-17 ⋅ 阅读:(34) ⋅ 点赞:(0)

在 MyBatis 中,缓存机制是为了提高数据库操作的性能,避免重复查询相同的数据。MyBatis 提供了两种缓存机制:一级缓存二级缓存

1. 一级缓存(Local Cache)

定义:
  • 一级缓存是 MyBatis 的默认缓存,它在 SqlSession 级别起作用,生命周期与 SqlSession 相同。也就是说,同一个 SqlSession 对象在多次执行相同的查询时,如果参数相同,第一次查询的结果会被缓存起来,后续的相同查询会直接从缓存中获取数据,而不再发送查询请求到数据库。
特点:
  • 默认启用:一级缓存默认是开启的,不需要做额外的配置。
  • 作用范围是 SqlSession:同一个 SqlSession 内有效,查询的数据在 SqlSession 关闭时缓存也会失效。
  • 根据查询参数缓存:如果查询的 SQL 和参数相同,则从缓存中读取结果;否则重新查询数据库。
  • 自动管理:MyBatis 自动管理一级缓存,不需要手动设置或操作。
何时清除缓存:
  • 每当执行 INSERTUPDATEDELETE 操作时,一级缓存会被清除。因为此时数据发生了变化,缓存内容可能已经不准确,必须重新查询数据库。
  • 调用 SqlSession.clearCache() 方法手动清空缓存。
  • SqlSession 关闭后,一级缓存也随之失效。
工作原理:
  1. 执行查询时,MyBatis 首先会去检查当前 SqlSession 中是否有相同的查询请求已经缓存过。
  2. 如果有,则直接返回缓存的结果;如果没有,则从数据库中查询,并将结果存入缓存,以便后续相同查询使用。
示例:
// 第一次查询
User user1 = sqlSession.selectOne("com.example.mapper.UserMapper.selectUserById", 1);

// 第二次查询,使用相同的SqlSession和参数,走缓存
User user2 = sqlSession.selectOne("com.example.mapper.UserMapper.selectUserById", 1);

System.out.println(user1 == user2);  // true,表示两次查询结果是同一个对象(走了缓存)

2. 二级缓存(Global Cache)

定义:
  • 二级缓存作用范围是 Mapper(映射器)级别,多个 SqlSession 可以共享相同的缓存数据。也就是说,同一个 Mapper 对象的查询结果可以跨 SqlSession 复用。
特点:
  • 默认关闭:二级缓存默认是关闭的,需要手动配置开启。
  • 作用范围是 Mapper:缓存是基于 Mapper 文件或 Mapper 接口的,二级缓存存储在 namespace 级别。
  • 缓存持久化:二级缓存中的数据可以被多个 SqlSession 共享,但每个 Mapper 都有自己的缓存区域,互不影响。
  • 基于对象序列化:缓存数据是通过对象序列化存储的,所以需要实体类实现 Serializable 接口。
何时失效:
  • 与一级缓存相似,INSERTUPDATEDELETE 操作会清除对应 namespace 下的缓存。
  • 在同一 Mapper 下的查询结果被缓存,不同 Mapper 之间不共享缓存。
开启二级缓存:
  1. 全局配置:在 mybatis-config.xml 中开启全局二级缓存支持。

    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    
  2. Mapper 级别配置:在每个 Mapper.xml 文件中开启二级缓存。

    <cache/>
    
  3. 实体类实现 Serializable:缓存的对象必须是可序列化的,因此要让实体类实现 Serializable 接口。

示例:
  1. 配置全局开启二级缓存:

    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    
  2. UserMapper.xml 中开启缓存:

    <mapper namespace="com.example.mapper.UserMapper">
        <cache/>
        <select id="selectUserById" parameterType="int" resultType="User">
            SELECT * FROM user WHERE id = #{id}
        </select>
    </mapper>
    
  3. 实体类 User

    public class User implements Serializable {
        private int id;
        private String name;
        private int age;
        // Getters and Setters
    }
    
工作原理:
  1. 当第一个 SqlSession 执行查询操作时,查询结果会被缓存到二级缓存中。
  2. 当第二个 SqlSession 执行相同查询操作时,会直接从二级缓存中读取数据,而不是再次查询数据库。
示例代码:
// 第一次查询,走数据库
SqlSession sqlSession1 = sqlSessionFactory.openSession();
User user1 = sqlSession1.selectOne("com.example.mapper.UserMapper.selectUserById", 1);
sqlSession1.commit();  // 提交事务后,查询结果会被放入二级缓存
sqlSession1.close();

// 第二次查询,走二级缓存
SqlSession sqlSession2 = sqlSessionFactory.openSession();
User user2 = sqlSession2.selectOne("com.example.mapper.UserMapper.selectUserById", 1);
sqlSession2.close();

System.out.println(user1 == user2);  // true,表示两次查询结果是同一个对象(走了二级缓存)

3. 一级缓存 vs 二级缓存

缓存类型 作用范围 生命周期 共享范围 默认状态
一级缓存 SqlSession SqlSession 生命周期 当前 SqlSession 内 默认开启
二级缓存 Mapper SqlSession 结束后持久化 跨 SqlSession 共享 默认关闭

4. 缓存清理条件

  • 一级缓存:每当执行 INSERTUPDATEDELETE 操作,或手动调用 clearCache(),缓存会被清空。
  • 二级缓存:每当执行 INSERTUPDATEDELETE 操作,相关 Mapper 下的缓存会被清空。

5. 缓存机制的使用场景

  • 一级缓存:适用于在同一个 SqlSession 中多次查询相同数据的场景,避免重复查询数据库。
  • 二级缓存:适用于跨多个 SqlSession 查询相同数据,尤其是在高并发场景下,可以显著减少数据库压力,提升性能。

总结

  • 一级缓存:默认开启,作用在 SqlSession 范围内,每个 SqlSession 独立管理缓存,生命周期短。
  • 二级缓存:默认关闭,需要手动开启,作用在 Mapper 范围内,多个 SqlSession 共享缓存,缓存内容可以跨会话。