mybatis一级缓存

1. 一级缓存概念

  • 什么是一级缓存:一级缓存也叫本地缓存,它是存在于一次SqlSession会话中。

  • 为什么需要缓存:缓存的提出简单来说就是为了降低与数据库的频繁交互,从而减轻服务器的压力。

  • 缓存的意义:在对数据库的一次SqlSession会话中,我们有可能会反复地执行完全相同的查询语句,为了防止短时间内频繁的访问数据库并且查询同一条语句,而查询一次的资源消耗很大。因此如果不采取一些必要的措施将会造成很大的资源浪费。

为了减少资源浪费问题,mybatis在SqlSession对象中建立了一个一级缓存(本地缓存),每次访问数据库之前先来缓存找,如果有之前完全一样的查询直接从缓存中取结果返回,如果本地缓存中找不到再与数据库进行交互。
在这里插入图片描述



2. 一级缓存原理

2.1、缓存的诞生过程

在这里插入图片描述

从SqlSessionFactory工厂中获得一个SqlSession会话对象时,SqlSession会创建一个Executor执行器,用于执行SQL语句。同时Executor会 代理 很多东西,事务、缓存、配置… 这里只讨论缓存,同时Executor会创建一个LocalCache。

注意:Executor是一个统称,Executor是一个大类,其中由很多执行器组成。


2.2、缓存的内部实现

在这里插入图片描述

package org.apache.ibatis.cache.impl;

import java.util.HashMap;
import java.util.Map;

import org.apache.ibatis.cache.Cache;
import org.apache.ibatis.cache.CacheException;

/**
 * @author Clinton Begin	   这是mybatis的作者
 */
public class PerpetualCache implements Cache {

  private final String id;

  private Map<Object, Object> cache = new HashMap<>();

  @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);
  }

  @Override
  public Object removeObject(Object key) {
    return cache.remove(key);
  }

  @Override
  public void clear() {
    cache.clear();
  }
}

Cache接口采用PerpetualCache实现类,而PerpetualCache内部真正的核心就是一个HashMap。既然是Key - Value键值对,Value毫无疑问肯定是查询到的结果,Key是针对SQL语句经过特殊运算的一串hashCode



3. 一级缓存的生命周期

在这里插入图片描述

3.1、缓存失效

这只是一级缓存大概的生命周期,不完全遵循这个原则。一级缓存大概受到4类操作的影响,会导致缓存更新、失效等问题。

  1. SqlSession.close()关闭会话直接导致所有的缓存释放

  2. Sqlsession.clearCache()清除一级缓存,释放所有的缓存

  3. 映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。



4. 一级缓存工作原理

4.1、本地缓存中存在

在这里插入图片描述
SqlSession传入SQL语句给Executro执行器,执行器进行hashCode运算。得到一个hashCode值,将hashCode值传给LocalCache缓存,缓存直接getValue(hashCode)获取查询结果

4.2、本地缓存中没有(包括各种失效)

在这里插入图片描述
只是多了一步将查询结果存入LocalCache的过程。



5. 简单测试

5.1、重复查询同一条语句
@Test
public void test1(){
    SqlSession Sqlsession = mybatisUtil.getSqlSession(true);
    UserMapper mapper = Sqlsession.getMapper(UserMapper.class);
    User user1 = mapper.getUserById(1);
    System.out.println(user1.toString());
    System.out.println("============================================");
    User user2 = mapper.getUserById(1);
    System.out.println(user2.toString());
	System.out.println("user1 == user2 ? " + (user1==user2));
    Sqlsession.close();
}

在这里插入图片描述

5.2、手动清除缓存
@Test
public void test2(){
    SqlSession Sqlsession = mybatisUtil.getSqlSession(true);
    UserMapper mapper = Sqlsession.getMapper(UserMapper.class);
    User user1 = mapper.getUserById(1);
    System.out.println(user1.toString());

    Sqlsession.clearCache();            //清除缓存

    System.out.println("============================================");
    User user2 = mapper.getUserById(1);
    System.out.println(user2.toString());

    Sqlsession.close();
}

在这里插入图片描述

5.3、insert、update、delete会刷新缓存

进行增删改操作后会清除缓存信息,这样做的原因是因为需要保持数据的一致性。防止出现脏读、幻读、不可重复读。哪怕是这三种操作对缓存中的一些数据不会产生影响都会重新读取。

@Test
public void test3(){
    SqlSession Sqlsession = mybatisUtil.getSqlSession(true);
    UserMapper mapper = Sqlsession.getMapper(UserMapper.class);
    User user1 = mapper.getUserById(1);
    System.out.println(user1.toString());

    mapper.updUser("123456",2);         //更改用户   2

    System.out.println("============================================");
    User user2 = mapper.getUserById(1);
    System.out.println(user2.toString());
    System.out.println("user1 == user2 ? " + (user1==user2));
    Sqlsession.close();
}

在这里插入图片描述

5.4、不同的SqlSession查询
@Test
    public void test4(){
        SqlSession Sqlsession = mybatisUtil.getSqlSession(true);
        UserMapper mapper = Sqlsession.getMapper(UserMapper.class);
        User user1 = mapper.getUserById(1);
        System.out.println(user1.toString());

        Sqlsession.close();
        System.out.println("============================================");

        Sqlsession = mybatisUtil.getSqlSession(true);
        mapper = Sqlsession.getMapper(UserMapper.class);
        User user2 = mapper.getUserById(1);
        System.out.println(user2.toString());
        System.out.println("user1 == user2 ? " + (user1==user2));
        Sqlsession.close();

    }

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值