欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 手游 > MyBatis 缓存机制详解

MyBatis 缓存机制详解

2025/2/6 11:55:49 来源:https://blog.csdn.net/Future_yzx/article/details/145393846  浏览:    关键词:MyBatis 缓存机制详解

目录

一、什么是缓存?

1. 什么是缓存?

2. 为什么使用缓存?

3. 什么样的数据适合使用缓存?

二、MyBatis 缓存机制

1. 一级缓存(也叫本地缓存)

2. 一级缓存失效的情况

3. 二级缓存

4. 二级缓存失效的情况

三、MyBatis 缓存查询顺序

四、MyBatis 缓存的高级配置


前言

        在高并发系统中,数据库查询是系统性能的瓶颈之一。为了提高查询效率,减少数据库的访问次数,缓存机制应运而生。MyBatis 作为一款优秀的 ORM 框架,内置了强大的查询缓存特性,支持一级缓存二级缓存两级缓存机制。本文将详细介绍缓存的概念、MyBatis 的缓存机制以及如何配置和使用 MyBatis 缓存。


一、什么是缓存?

1. 什么是缓存?

缓存是存储在内存中的数据。
当用户查询数据时,系统可以直接从缓存中获取,而不需要访问数据库,从而提升查询效率。

2. 为什么使用缓存?

  • 减少数据库交互,降低系统的开销。
  • 提高查询效率,优化系统性能。
  • 支持高并发,避免数据库成为系统瓶颈。

3. 什么样的数据适合使用缓存?

  • 经常被查询
  • 变化不频繁

对于频繁变更的数据(如订单状态),缓存并不适用,因为数据不一致的风险较高。


二、MyBatis 缓存机制

MyBatis 内置了强大的缓存机制,支持两级缓存

  • 一级缓存(本地缓存):默认开启,作用域为 SqlSession 级别
  • 二级缓存(全局缓存):需要手动开启,作用域为 SqlSessionFactory 级别

1. 一级缓存(也叫本地缓存)

         在使用一级缓存后,与数据库第一次会话(SqlSession )期间查询到的数据会被放入本地缓存当中。如果在同一个会话后续需要获取相同的数据,可以直接从缓存中获取,而没必要再去查询数据库

(1)一级缓存的特点
  • 默认开启,不需要额外配置。
  • 作用域是SqlSession 级别,即同一个 SqlSession 多次执行相同查询,结果会被缓存
  • 不同 SqlSession 之间缓存互不影响
(2)一级缓存示例
@Test
public void findById() throws IOException {// 加载配置文件InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);// 创建 SqlSessionSqlSession session = factory.openSession();UserDao mapper = session.getMapper(UserDao.class);// 第一次查询User user1 = mapper.findById(1);System.out.println(user1.toString());// 第二次查询(相同的查询)User user2 = mapper.findById(1);System.out.println(user2.toString());// 判断两次查询结果是否相同System.out.println(user1 == user2); // true,说明数据来自缓存session.close();in.close();
}

运行如下:

结论:同一个 SqlSession (会话)下,第一次查询的数据会缓存,第二次查询相同数据时直接从缓存中获取,不会执行 SQL 语句。


2. 一级缓存失效的情况

以下情况会导致 MyBatis 一级缓存失效:

(1).不同 SqlSession

如果两次查询使用的是不同的 SqlSession,则缓存不会共享,查询会直接访问数据库。

(2).查询条件不同
因为查询条件不同,缓存未命中。

mapper.findById(1);
mapper.findById(2);

(3).执行了增删改操作

任何增删改操作都会清空 SqlSession 的缓存,以确保数据一致性。

mapper.findById(1);
mapper.updateUser(user);
mapper.findById(1);

 

(4).手动清除缓存
手动清除一级缓存后,查询将重新访问数据库。

session.clearCache();


3. 二级缓存

(1)二级缓存的特点
  • 默认关闭,需要手动开启。
  • 作用域是SqlSessionFactory 级别,即同一 SqlSessionFactory 产生的多个 SqlSession 共享缓存
  • 缓存的数据是对象的副本,而不是对象本身(即缓存的是数据,不是对象实例)。
(2)开启二级缓存的条件
  1. 在核心配置文件(SqlMapConfig.xml)中开启全局缓存

    <settings><setting name="cacheEnabled" value="true"/>
    </settings>
    
  2. 在对应的 Mapper 配置文件中声明使用二级缓存

    <!--使用二级缓存-->
    <cache/>
    
  3. 实体类必须实现 Serializable 接口

    public class User implements Serializable {private Integer id;private String username;private Date birthday;private String sex;private String address;
    }
    
  4. SqlSession 关闭或提交后,数据才会进入二级缓存

    @Test
    public void findById() throws IOException {// 1.加载SqlMapConfig配置文件InputStream resourceAsStream = Resources.getResourceAsStream("SqlMapConfig.xml");//2.创建sqlSessionFactory工厂SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(resourceAsStream);//3.sqlSessionFactory创建sqlSessionSqlSession sqlSession = factory.openSession();SqlSession sqlSession2 = factory.openSession();//4.通过Session创建UserDao接口代理对象UserDao mapper = sqlSession.getMapper(UserDao.class);User user1 = mapper.findById(1);System.out.println(user1.toString());// 将其一级缓存的数据放进二级缓存中,并清空一级缓存sqlSession.close();System.out.println("-----------------");UserDao mapper2 = sqlSession2.getMapper(UserDao.class);User user2 = mapper2.findById(1);System.out.println(user2.toString());// 将其一级缓存的数据放进二级缓存中,并清空一级缓存sqlSession2.close();System.out.println(user1 == user2);resourceAsStream.close();
    }
    

 运行结果:

 最后输出false,证明user1和user2并不是同一个对象;得出一下结论:

结论: 二级缓存存储的是数据,而不是对象,因此即使查询相同数据,返回的对象实例仍然不同。 


4. 二级缓存失效的情况

  • 执行了增删改操作:会清空一级缓存和二级缓存,以保证数据一致性。

三、MyBatis 缓存查询顺序

  1. 优先查询二级缓存
    因为二级缓存是 SqlSessionFactory 级别,多个 SqlSession 可能已经缓存了数据。
  2. 如果二级缓存未命中,则查询一级缓存
  3. 如果一级缓存也未命中,则查询数据库
  4. SqlSession 关闭后,一级缓存数据会写入二级缓存


四、MyBatis 缓存的高级配置

Mapper.xml 文件中,可以自定义缓存策略:

<cache eviction="FIFO"flushInterval="60000"size="512"readOnly="true"/>

Catch参数的具体细节说明:

eviction(收回策略)

  • LRU(最近最少使用的):移除最长时间不被使用的对象,这是默认值。
  • FIFO(先进先出):按对象进入缓存的顺序来移除它们。
  • SOFT(软引用):移除基于垃圾回收器状态和软引用规则的对象。
  • WEAK(弱引用):更积极地移除基于垃圾收集器状态和弱引用规则的对象。

flushinterval(刷新间隔)

  • 可以被设置为任意的正整数,单位是毫秒。
  • 默认情况不设置,即没有刷新间隔,缓存仅仅在调用语句时刷新。

size(缓存容量)

  • 最大缓存对象数,可以被设置为任意正整数,默认值是1024 。

readOnly(只读) 属性可以被设置为 true / false。

  • true只读缓存:所有调用者获取到的都是缓存对象本身,并且不能对其进行修改。 这提供了很重要的性能优势。
  • false读写缓存: 通过序列化返回缓存对象的拷贝版,这种方式会慢一些,但是安全,因此默认是 false。

五、总结

  • 一级缓存:默认开启,作用域是 SqlSession,缓存的是 查询结果SqlSession 关闭后失效
  • 二级缓存:默认关闭,作用域是 SqlSessionFactory,多个 SqlSession 共享,需手动开启,SqlSession 关闭后数据进入二级缓存
  • 缓存查询顺序:二级缓存 → 一级缓存 → 数据库。
  • 缓存失效情况:SqlSession 关闭、执行增删改操作、手动清除缓存等。

合理使用 MyBatis 缓存,可以有效提高查询性能,减少数据库访问压力,提高系统并发能力。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com