Mybatis知识小汇(13)——缓存(二级缓存)

本文详细介绍了MyBatis的二级缓存机制,包括其工作原理、配置步骤以及实际测试案例。二级缓存作为全局缓存,能够在会话关闭时将一级缓存中的数据保存,供新的会话查询使用,提高数据读取效率。开启二级缓存的配置包括在MyBatis的全局设置中启用,并在Mapper中进行相应定义。测试结果显示,二级缓存能够有效地在不同会话间共享数据。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

文章目录

二级缓存
  • 二级缓存也叫全局缓存,一级缓存作用域太低,所以诞生了二级缓存
  • 基于namespace级别的缓存,一个名字空间对应一个二级缓存
  • 工作机制
    • 一个会话查询一条数据,这个数据就会被放在当前会话的一级缓存中
    • 如果当前会话关闭一级缓存也就会消失,但是我们想要的是会话关闭时,一级缓存中的数据保存到二级缓存中
    • 新的会话查询信息,就可以从二级缓存中获取
    • 不同的mapper查询数据会放在自己对应的缓存(map)中

步骤:

  1. 开启全局缓存

    <settings>
        <!--        显示开启全局缓存,默认也是true-->
        <setting name="cacheEnabled" value="true"/>
    </settings>
    
  2. 在要使用二级缓存的Mapper中定义
    需要实现序列化

    <cache/>
    

    也可以

    <!--    在当前Mapper.xml中使用二级缓存-->
    <cache
           eviction="FIFO"
           flushInterval="60000"
           size="512"
           readOnly="true"/>
    

3. [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zumyVHFh-1613533755250)(Mybatis.assets/image-20210217113119674.png)]

  1. 测试

    1. 未开启二级缓存

      public class UserMapperTest {
          @Test
          public void selectById(){
              SqlSession sqlSession = MybatisUtils.getSqlSession();
              SqlSession sqlSession1 = MybatisUtils.getSqlSession();
      
              UserMapper mapper = sqlSession.getMapper(UserMapper.class);
              UserMapper mapper1 = sqlSession1.getMapper(UserMapper.class);
      
              User user = mapper.selectById(1);
              System.out.println(user);
              sqlSession.close();
              System.out.println("==================================================");
              User user1 = mapper1.selectById(1);
              System.out.println(user1);
      
              System.out.println(user == user1);
              sqlSession1.close();
          }
      }
      

在这里插入图片描述

  1. 开启二级缓存

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5gpfdE3I-1613533755253)(Mybatis.assets/image-20210217114551771.png)]

小结:

  1. 只要开启了二级缓存,在同一个Mapper下都有效
  2. 所有数据都会先放在一级缓存中
  3. 当提交数据或者关闭连接时,才会放到二级缓存中
    上一节–>一级缓存
    如有不对的地方欢迎指出,共同进步!
### MyBatis 一级缓存源码分析 MyBatis 的一级缓存主要作用于同一个 `SqlSession` 实例内,在一次会话期间,查询的结果会被保存在该会话的本地缓存中。当再次发起相同的 SQL 查询请求时,如果参数相同,则不会向数据库发送新的查询命令而是直接返回缓存中的结果。 #### Cache 接口及其实现类 为了支持不同类型的缓存机制,MyBatis 定义了一个通用的 `Cache` 接口,并提供多种具体的实现方式。对于一级缓存而言,通常采用的是基于内存的方式,即通过 `PerpetualCache` 类来管理缓存条目[^1]。 ```java public class PerpetualCache implements Cache { private final String id; private final Map<Object, Object> cache = new HashMap<>(); public PerpetualCache(String id) { this.id = id; } @Override public String getId() { return id; } @Override public int getSize() { return cache.size(); } @Override public void putObject(Object key, Object value) { cache.put(key, value); } @Override public Object getObject(Object key) { return cache.get(key); } } ``` 这段代码展示了如何创建一个简单的哈希表用于存储键值对形式的对象实例,其中包含了获取对象(`getObject`)置对象(`putObject`)以及计算大小(`getSize`)的方法。 #### CacheKey 缓存项的关键字生成逻辑 每次执行查询操作之前都会先构建唯一的 `CacheKey` 对象作为缓存查找依据。这个过程涉及到多个因素如 SQL 文本本身、传入参数列表等信息共同参与 hashcode 计算形成最终唯一标识符。 ```java public class CacheKey { private static final int DEFAULT_MULTIPLYER = 37; private int hashCode = 0; private List<Object> updateList = new ArrayList<>(8); // 构造函数... /** * 更新当前 CacheKey 值. */ public synchronized void update(Object object) { ... } /** * 获取此 CacheKey 的散列码 (hashCode). */ @Override public int hashCode(){ ... } /** * 判断两个 CacheKey 是否相等. */ @Override public boolean equals(Object obj){ ... } } ``` 上述方法确保了即使面对复杂的查询条件组合也能准确无误地区分不同的查询语句并正确命中对应的缓存记录。 --- ### MyBatis 二级缓存源码分析 相比于一级缓存仅限于单次会话范围内的数据共享,二级缓存则跨越整个应用程序生命周期甚至多台服务器之间进行持久化级别的资源共享。它按照命名空间(namespace 或 Mapper 文件)级别工作,意味着同一 mapper 下的所有 sql 映射都可以访问到统一份缓存副本[^3]。 #### 解决脏读问题 为了避免并发环境下可能发生的脏读现象——即某个线程更新了一部分数据但在未完成提交前就被其他线程读取到了旧版本的内容——MyBatis 使用了名为 `TransactionalCache` 的特殊结构处理写回型缓存操作。具体来说就是在事务真正结束之后才允许新加入的数据进入公共可见区域;而在那之前这些临时变更只会存在于私有队列里等待同步时刻的到来。 #### 自定义外部缓存方案集成 考虑到实际生产环境中往往需要更高级别的性能优化措施或是跨集群间的协同作业需求,MyBatis 还开了对外部组件的支持能力以便开发者能够灵活选用适合业务场景的技术栈。例如借助 Redis 提供分布式的高速缓存服务可以有效缓解因频繁 IO 导致的压力瓶颈同时也规避掉了传统 JVM 内存局限所带来的风险隐患[^2]。 ```xml <dependencies> <dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-redis</artifactId> <version>1.0.0-beta2</version> </dependency> </dependencies> <!-- 在Mapper XML文件中 --> <cache type="org.mybatis.caches.redis.RedisCache"/> ``` 以上配置片段说明了怎样引入第三方库并通过修改映射文档指定特定类型的缓存处理器从而达到增强功能的目的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值