在MyBatis中,一级缓存和二级缓存有何不同?

参考回答

在 MyBatis 中,一级缓存二级缓存有以下几方面的主要区别:

  1. 作用范围不同
    • 一级缓存:作用范围是 SqlSession。每一个 SqlSession 都有自己独立的一级缓存。当你在同一个 SqlSession 中执行多次相同的查询时,MyBatis 会使用一级缓存来避免重复查询数据库。一级缓存只在 SqlSession 生命周期内有效,一旦 SqlSession 关闭,缓存就会被清除。
    • 二级缓存:作用范围是 SqlSessionFactory,即跨 SqlSession。多个 SqlSession 可以共享二级缓存。当你在不同的 SqlSession 中执行相同的查询时,MyBatis 会首先检查二级缓存是否存在该结果,如果存在,则直接从缓存中获取数据,而不必再次查询数据库。
  2. 缓存存储位置不同
    • 一级缓存:一级缓存存储在 SqlSession 内部内存中,每次查询时都在 SqlSession 内部查找。如果缓存命中,直接返回结果;如果未命中,则执行 SQL 查询并缓存数据。
    • 二级缓存:二级缓存存储在 SqlSessionFactory 范围内,可以通过配置将缓存存储在外部存储系统中(如 EHCacheRedis 等),或者在内存中存储。二级缓存可以跨多个 SqlSession 共享缓存数据。
  3. 生命周期不同
    • 一级缓存:缓存数据的生命周期与 SqlSession 一致。每次打开新的 SqlSession 时,一级缓存都会被清空;每次 SqlSession 提交或回滚事务时,一级缓存会被刷新。
    • 二级缓存:缓存数据的生命周期与 SqlSessionFactory 一致。只要不清除,二级缓存中的数据可以跨多个 SqlSession 存活,直到缓存清除或过期。
  4. 配置与启用方式不同
    • 一级缓存:一级缓存是 默认启用 的,无法关闭。每次打开 SqlSession 时都会启用一级缓存,开发者不需要手动配置。
    • 二级缓存:二级缓存需要在 MyBatis 配置文件和映射器文件中进行显式配置。例如,在 mybatis-config.xml 中启用二级缓存,并在 Mapper 文件中为每个映射器启用二级缓存。
  5. 性能和粒度不同
    • 一级缓存:一级缓存通常用于减少同一 SqlSession 内部重复查询的开销,因此它的缓存粒度较小,适用于单一会话中的查询优化。
    • 二级缓存:二级缓存跨 SqlSession 有更大的缓存粒度,适用于多次查询相同数据的场景。二级缓存能够有效减少数据库访问次数,特别是在系统负载较大时,能够显著提升性能。

详细讲解与拓展

  1. 一级缓存的工作原理
  • 作用范围:每个 SqlSession 内都有自己独立的一级缓存,当执行 SQL 查询时,MyBatis 会首先检查一级缓存中是否已经存有该查询的结果。如果缓存中存在数据,就直接从缓存中返回,而不再查询数据库。

  • 生命周期:一级缓存的生命周期与 SqlSession 的生命周期相同。当 SqlSession 被关闭时,一级缓存会被清空。当 SqlSession 提交或回滚事务时,一级缓存会被刷新。

  • 清空时机:如果执行了 commitrollback 操作,一级缓存会被刷新。此外,当执行增、删、改操作时,也会使得一级缓存的数据失效。

  • 示例

    “`java
    SqlSession sqlSession = sqlSessionFactory.openSession();
    // 第一次查询,从数据库获取
    User user1 = sqlSession.selectOne("com.example.UserMapper.selectUserById", 1);
    // 第二次查询,相同的 SQL,结果从一级缓存中获取
    User user2 = sqlSession.selectOne("com.example.UserMapper.selectUserById", 1);
    sqlSession.close(); // 关闭时一级缓存清空
    “`

  1. 二级缓存的工作原理
  • 作用范围:二级缓存跨 SqlSession 存在,所有通过相同 SqlSessionFactory 创建的 SqlSession 对象可以共享二级缓存。如果在不同的 SqlSession 中执行相同的查询操作,MyBatis 会首先检查二级缓存中是否存在该数据。如果有,直接从缓存中返回。

  • 生命周期:二级缓存的生命周期与 SqlSessionFactory 绑定,可以跨 SqlSession 存活。二级缓存的数据不会随着 SqlSession 的关闭而清空,直到应用关闭或缓存被手动清理。

  • 清空时机:二级缓存中的数据会在执行 updateinsertdelete 等修改数据的操作时失效,通常需要通过 flush 来手动刷新缓存。二级缓存的失效机制相对较复杂,需要开发者手动管理。

  • 示例

    “`xml
    <mapper namespace="com.example.UserMapper">
    <cache/> <!– 启用二级缓存 –>
    <select id="selectUserById" resultType="User">
    SELECT * FROM users WHERE id = #{id}
    </select>
    </mapper>
    “`

    • mybatis-config.xml 中启用全局缓存:
      <configuration>
         <settings>
             <setting name="cacheEnabled" value="true"/>
         </settings>
      </configuration>
      
      XML
  1. 一级缓存和二级缓存的区别
  • 作用范围:一级缓存是 SqlSession 范围内的缓存,二级缓存是 SqlSessionFactory 范围内的缓存。
  • 缓存存储位置:一级缓存存储在内存中,每个 SqlSession 内部独立存储;二级缓存可以使用外部缓存框架(如 EHCacheRedis)来持久化存储,也可以存在内存中。
  • 生命周期:一级缓存随着 SqlSession 的生命周期而存在,SqlSession 关闭时缓存清空;二级缓存的生命周期与 SqlSessionFactory 一致,可以跨 SqlSession 存活。
  • 启用方式:一级缓存是 MyBatis 默认启用的,二级缓存需要在 MyBatis 配置文件中手动启用。
  1. 缓存的使用场景
  • 一级缓存:适用于同一个 SqlSession 内的多次查询。例如,处理单次请求时,多次查询同一数据,可以利用一级缓存来避免重复查询数据库。

  • 二级缓存:适用于多个 SqlSession 或全局查询共享的场景。例如,多个用户查询相同的数据,或在多次相同的查询中需要减少数据库访问,二级缓存可以显著提高性能。

总结

一级缓存和二级缓存是 MyBatis 提供的两种缓存机制。一级缓存作用范围较小,只在同一个 SqlSession 内有效,用于减少同一会话内的重复查询;而二级缓存跨多个 SqlSession,可以在更大的范围内共享数据,显著减少数据库访问。一级缓存默认启用,不需要开发者配置,而二级缓存需要在配置文件中显式启用并进行配置。正确使用缓存可以显著提高查询性能,但需要注意缓存的失效机制,以避免出现过时的数据。

发表评论

后才能评论