MyBatis中的缓存机制有什么作用,它是如何工作的?

参考回答

MyBatis 提供了缓存机制来优化数据库查询性能,减少不必要的数据库访问。MyBatis 的缓存机制主要包括 一级缓存二级缓存

  1. 一级缓存
    一级缓存是 SqlSession 范围内的缓存。每次执行 SQL 查询时,MyBatis 会首先检查缓存中是否已经存在查询结果。如果有,直接返回缓存中的结果;如果没有,则会向数据库发送查询请求,并将查询结果存入缓存。
  • 作用:避免同一 SqlSession 内重复查询相同的数据,提升性能。
  1. 二级缓存
    二级缓存是 SqlSessionFactory 范围内的缓存,它跨 SqlSession 存在。多个 SqlSession 可以共享同一个二级缓存。二级缓存通常是通过缓存框架(如 EHCacheRedis)来实现的。
  • 作用:在多个 SqlSession 之间共享缓存,减少数据库的访问次数,提升性能。

详细讲解与拓展

1. 一级缓存(SqlSession 缓存)

一级缓存是 MyBatis 默认启用的缓存,它在 SqlSession 对象的生命周期内有效。当一个 SqlSession 被创建时,它会开启一级缓存,每次查询都会先查询一级缓存。如果缓存中存在该查询的结果,则直接返回缓存的结果,不会发送 SQL 请求到数据库。只有在缓存中没有找到数据时,才会查询数据库,并将结果存入缓存。

  • 缓存命中:当 SqlSession 执行同一个查询时,第一次查询会从数据库中获取数据,之后如果再次执行相同的查询,MyBatis 会直接从缓存中获取数据,而不会再次查询数据库。

  • 缓存清空:在执行 commitrollback 操作时,一级缓存会被清空。也就是说,一级缓存的数据是与当前 SqlSession 绑定的,SqlSession 关闭时缓存会失效。

  • 举例

    SqlSession sqlSession = sqlSessionFactory.openSession();
    User user1 = sqlSession.selectOne("selectUserById", 1); // 从数据库查询
    User user2 = sqlSession.selectOne("selectUserById", 1); // 从一级缓存获取
    sqlSession.close(); // 关闭时清空一级缓存
    

2. 二级缓存(跨 SqlSession 缓存)

二级缓存是 SqlSessionFactory 范围内的缓存,它允许跨 SqlSession 对象共享缓存数据。二级缓存是通过在 MyBatis 配置文件中启用和配置的,可以使用不同的缓存实现,如 EHCacheRedis 等。

  • 启用二级缓存:在 mybatis-config.xml 配置文件中,需要配置开启二级缓存,并且在每个映射器(Mapper)中单独配置二级缓存。

  • 缓存机制:当查询数据时,如果数据不在一级缓存中,MyBatis 会尝试在二级缓存中查找。如果找不到数据,则会从数据库中查询,并将查询结果存入二级缓存中,供其他 SqlSession 共享使用。

  • 举例

    • 配置二级缓存
    <configuration>
        <settings>
            <setting name="cacheEnabled" value="true"/>
        </settings>
        <mappers>
            <mapper resource="com/example/UserMapper.xml"/>
        </mappers>
    </configuration>
    
    • 启用 Mapper 缓存
    <mapper namespace="com.example.UserMapper">
        <cache/>
        <select id="selectUserById" resultType="User">
            SELECT * FROM users WHERE id = #{id}
        </select>
    </mapper>
    
  • 缓存清空:与一级缓存不同,二级缓存的清空是由外部手动控制的。当执行 deleteupdateinsert 等操作时,需要手动清除二级缓存中的相关数据,否则缓存中的数据可能会过期。

  • 举例

    SqlSession sqlSession1 = sqlSessionFactory.openSession();
    User user1 = sqlSession1.selectOne("com.example.UserMapper.selectUserById", 1); // 查询并缓存
    sqlSession1.commit(); // 提交事务
    sqlSession1.close();  // 关闭时,缓存数据保存至二级缓存
    
    SqlSession sqlSession2 = sqlSessionFactory.openSession();
    User user2 = sqlSession2.selectOne("com.example.UserMapper.selectUserById", 1); // 从二级缓存读取
    sqlSession2.close();
    

3. 缓存的工作原理

  • 缓存存储:MyBatis 的缓存机制会将查询结果保存到缓存中,存储的是以查询条件为 key、查询结果为 value 的键值对。一级缓存存储在 SqlSession 内存中,而二级缓存存储在文件、数据库或内存缓存框架(如 EHCache)中。

  • 缓存策略:缓存策略控制缓存的生存周期、更新时机等。例如,MyBatis 支持懒加载(Lazy Load)和自动清除(Auto Flush)等策略。

  • 缓存的失效机制:缓存数据通常会有失效时间,例如,当数据库中的数据被更新或删除时,缓存中的数据需要清空或更新。这通常通过触发缓存的清除或更新操作来实现。

4. 配置与使用二级缓存

  1. 配置全局二级缓存
    mybatis-config.xml 文件中启用缓存:

    <configuration>
       <settings>
           <setting name="cacheEnabled" value="true"/> <!-- 启用二级缓存 -->
       </settings>
    </configuration>
    
  2. 配置 Mapper 缓存
    每个 Mapper 可以单独配置是否启用缓存:

    <mapper namespace="com.example.UserMapper">
       <cache/>
       <select id="selectUserById" resultType="User">
           SELECT * FROM users WHERE id = #{id}
       </select>
    </mapper>
    
  3. 自定义缓存实现
    MyBatis 默认使用内存缓存,但你可以通过配置来使用其他缓存实现,如 EHCacheRedis

    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
    

5. 缓存失效与更新

  • 当执行 updateinsertdelete 操作时,相关的数据缓存会失效。
  • 如果开启了二级缓存并且执行了某些操作(如 update),MyBatis 会自动清空缓存。
  • 二级缓存的更新机制可以通过 缓存刷新策略缓存失效时间 来控制。

总结

MyBatis 提供了强大的缓存机制,主要通过 一级缓存二级缓存 来减少数据库访问,提高性能。一级缓存是 SqlSession 范围内的缓存,只在当前 SqlSession 内有效;二级缓存是跨 SqlSession 共享的缓存,存储在内存中或者外部缓存框架(如 EHCacheRedis)中。通过配置二级缓存,MyBatis 可以显著减少数据库访问,优化查询性能。不过,需要注意的是,缓存中的数据可能会过时,因此需要在适当的时候清除缓存以保证数据的正确性。

发表评论

后才能评论