【Mybatis】一级缓存和二级缓存

news2024/11/27 12:16:49

【Mybatis】一级缓存和二级缓存

  • (一)为什么需要缓存
  • (二)一级缓存(在SqlSession上缓存)
    • 【1】示例代码
    • 【2】增删改操作会刷新一级缓存
    • 【3】一级缓存流程总结
        • (1)一级缓存简介
        • (2)何时清空一级缓存
        • (3)一级缓存无过期时间,只有生命周期
  • (三)一级缓存底层原理
  • (四)二级缓存(在SqlSessionFactory上缓存)
    • 【1】二级缓存需要手动配置开启
    • 【2】示例代码
    • 【3】二级缓存流程总结
        • (1)二级缓存简介
        • (2)二级缓存何时存入
        • (3)二级缓存有过期时间,但没有后台线程进行检测
        • (4)一级缓存和二级缓存的执行顺序
  • (五)二级缓存底层原理
  • (六)注意事项

(一)为什么需要缓存

缓存一般用在可高速读写的存储器上,为提高速度,可以暂时把常用的数据缓存在内存中,这样读取速度就会远快于读取磁盘的速度

(二)一级缓存(在SqlSession上缓存)

【1】示例代码

public class TestMybatis {

    private InputStream inputStream;
    private SqlSessionFactory sqlSessionFactory;
    private SqlSession session;
    private ICategoryDao categoryDao;

    @Before
    public void init() throws Exception{
//        1-读取配置文件(拿到资源)
        inputStream= Resources.getResourceAsStream("mybatis_Config.xml");
//        2-创建工厂(把资源给构建者)
        sqlSessionFactory=new SqlSessionFactoryBuilder().build(inputStream);
//        3-使用工厂生产SQLSession对象
        session=sqlSessionFactory.openSession(true);//true以后就不需要自己提交了
//        4-使用SQLSession创建Dao接口的代理对象(使用反射获取字节码class)
        categoryDao=session.getMapper(ICategoryDao.class);
//        5-使用代理对象执行方法,结果放在List中,并且循环遍历
    }

    @After
    public void destory() throws Exception{
//        6-释放资源
        session.close();
        inputStream.close();
    }

    @Test
    public void testFirstLevelCache(){
//        下面这个语句可以清空缓存,然后重新开启
//        session.clearCache();
        categoryDao=session.getMapper(ICategoryDao.class);
        Category c1=categoryDao.selectOne(1);
        System.out.println(c1);
        Category c2=categoryDao.selectOne(1);
        System.out.println(c2);

//      只发起了一次查询,结果表明两次取出的是同一个值
        System.out.println(c1==c2);
    }
}

在这里插入图片描述

可以看到,当使用categoryDao=session.getMapper(ICategoryDao.class);后,数据就缓存放在SQLSession中了,后面进行了两个同条件的检索c1和c2,但是它俩都是从SQLSession里取的数据,sql语句只在第一次检索的时候执行了,第二次检索的时候没有执行,而是直接到缓存里取数据,最后的输出值为true。

但是SQLSession层面的缓存要求必须是同一个SQLSession对象,如果是不同的对象,就无法获取到缓存数据。要想实现不同的SQLSession对象也能获取同样的缓存数据,就要继续往上层去缓存,也就是把数据缓存在SqlSessionFactory上。

【2】增删改操作会刷新一级缓存

而每次增删改操作都有可能会改变原来的数据,所以必须刷新清空一级缓存。
在这里插入图片描述

【3】一级缓存流程总结

(1)一级缓存简介

一级缓存作用域是sqlsession级别的,同一个sqlsession中执行相同的sql查询(相同的sql和参数),第一次会去查询数据库并写到缓存中,第二次从一级缓存中取。

一级缓存是基于 PerpetualCache 的 HashMap 本地缓存,默认打开一级缓存。

(2)何时清空一级缓存

如果中间sqlSession去执行commit操作(执行插入、更新、删除),则会清空SqlSession中的一级缓存,这样做的目的为了让缓存中存储的是最新的信息,避免脏读。

一级缓存时执行commit,close,增删改等操作,就会清空当前的一级缓存;当对SqlSession执行更新操作(update、delete、insert)后并执行commit时,不仅清空其自身的一级缓存(执行更新操作的效果),也清空二级缓存(执行commit()的效果)。

(3)一级缓存无过期时间,只有生命周期

MyBatis在开启一个数据库会话时,会创建一个新的SqlSession对象,SqlSession对象中会有一个Executor对象,Executor对象中持有一个PerpetualCache对象,见下面代码。当会话结束时,SqlSession对象及其内部的Executor对象还有PerpetualCache对象也一并释放掉。

(三)一级缓存底层原理

在这里插入图片描述

(四)二级缓存(在SqlSessionFactory上缓存)

【1】二级缓存需要手动配置开启

二级缓存是全局的,也就是说;多个请求可以共用一个缓存,二级缓存需要手动开启,有2种方式配置二级缓存:
(1)缓存会先放在一级缓存中,当sqlSession会话提交或者关闭时才会将一级缓存刷新到二级缓存中;
(2)开启二级缓存后,用户查询时,会先去二级缓存中找,找不到在去一级缓存中找;

(1)第一种配置方式
单个mapper配置,主需要在需要开启二级缓存的mapper.xml文件中加入以下配置即可开启

 <!-- 开启单个mapper的二级缓存,也叫全局缓存-->
  <cache />

注意一定要加到xxMapper.xml的文件内,千万不要加到mybatis 的主配置文件里面了,会报错的

(2)第二种配置方式
所有的mapper都开启二级缓存,在mybatis.xml中加入以下配置即可,只需要在配置文件中加上如下配置:

<!--打开延迟加载-->
    <settings>
        <!-- 打开延迟加载的开关 -->
        <setting name="lazyLoadingEnabled" value="true" />
        <!-- 将积极加载改为消息加载即按需加载 -->
        <setting name="aggressiveLazyLoading" value="false"/>
        <!-- 打开二级缓存 -->
        <setting name="cacheEnabled" value="true"/>
    </settings>

【2】示例代码

不同的SQLSession对象在获取同一条记录的时候,都是只在第一次检索的时候才会执行sql语句,后面的检索都不再执行sql,而是直接到缓存里找。正是因为SQLSession是由SqlSessionFactory生成的,而数据也缓存在SqlSessionFactory中,所以不同的SQLSession对象能够获取到相同的缓存数据。

实例代码

public static void main(String[] args) throws IOException {

    // 加载mybatis配置文件
    Reader reader = Resources.getResourceAsReader("config/configuration.xml");
    //创建数据工厂
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();

    SqlSessionFactory sqlSessionFactory = builder.build(reader);

    // 第一个会话
    SqlSession sqlSession = sqlSessionFactory.openSession(true);


    // 获取会话一的mapper接口对象
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);

    // 第一次查询
    User user = mapper.selectByPrimaryKey("3rfrf34r34");
    

    //释放第一个会话
    sqlSession.clearCache();
    sqlSession.close();

    // 第二个会话
    SqlSession sqlSession2 = sqlSessionFactory.openSession(true);
    // 获取会话二的mapper接口对象
    UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);

    // 第二次查询
    User user1 = mapper2.selectByPrimaryKey("3rfrf34r34");
    // 释放第二个会话
    sqlSession2.clearCache();
    sqlSession2.close();
}

打印结果
在这里插入图片描述

【3】二级缓存流程总结

(1)二级缓存简介

它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFactory对象创建的SqlSession共享其缓存。

二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。

(2)二级缓存何时存入

在关闭sqlsession后(close),才会把该sqlsession一级缓存中的数据添加到namespace的二级缓存中。

开启了二级缓存后,还需要将要缓存的pojo实现Serializable接口,为了将缓存数据取出执行反序列化操作,因为二级缓存数据存储介质多种多样,不一定只存在内存中,有可能存在硬盘中。

(3)二级缓存有过期时间,但没有后台线程进行检测

需要注意的是,并不是key-value的过期时间,而是这个cache的过期时间,是flushInterval,意味着整个清空缓存cache,所以不需要后台线程去定时检测。

每当存取数据的时候,都有检测一下cache的生命时间,默认是1小时,如果这个cache存活了一个小时,那么将整个清空一下。

(4)一级缓存和二级缓存的执行顺序

当 Mybatis 调用 Dao 层查询数据库时,先查询二级缓存,二级缓存中无对应数据,再去查询一级缓存,一级缓存中也没有,最后去数据库查找。

(五)二级缓存底层原理

在这里插入图片描述

(六)注意事项

另外,缓存还有以下几种情况需要注意
(1)映射语句文件中的所有 select 语句的结果将会被缓存。
(2)映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。
(3)缓存会使用最近最少使用算法(LRU, Least Recently Used)算法来清除不需要的缓存。
(4)缓存不会定时进行刷新(也就是说,没有刷新间隔)。
(5)缓存会保存列表或对象(无论查询方法返回哪种)的 1024 个引用。
(6)缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/74010.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

多点DMALL冲刺港股:年亏损超9亿 腾讯IDG金蝶是股东

雷递网 雷建平 12月8日多点数智有限公司&#xff08;简称&#xff1a;“多点数智”&#xff09;日前递交招股书&#xff0c;准备在港交所上市。年亏损超9亿多点DMALL成立于2015年&#xff0c;为本地零售业提供基于云的一站式端到端的数字零售SaaS平台。多点DMALL提供的服务包括…

搜索是过拟合的生成;生成是欠拟合的搜索

神经搜索的最大竞争者可能来自于一种甚至不需要向量嵌入作为中间表示的技术 —— 一种直接返回你想要的结果的端到端技术。"那么&#xff0c;谁将是神经搜索最大的竞争对手&#xff1f;"本文作者&#xff1a;肖涵&#xff0c;Jina AI 创始人兼 CEO 谁将是神经搜索最大…

Redis框架(二):SpringDataRedis入门和序列化方式解决内存占用问题

SpringDataRedis入门和序列化方式解决内存占用问题基本介绍实例Demo自定义RedisTemplate序列化自定义的RestTemplate的内存占用问题StringRedisTemplate解决内存占用问题总结SpringCloud章节复习已经过去&#xff0c;新的章节Redis开始了&#xff0c;这个章节中将会回顾Redis 主…

c#入门-可选参数,不定长参数

可选参数 声明可选参数 函数的参数在声明时&#xff0c;可以同时为其赋值一个常量。 但是所有这样的参数&#xff0c;需要在所有必填参数的后面。 void Any(int i 10) {Console.WriteLine(i); }使用可选参数 稍后&#xff0c;在调用函数时&#xff0c;你可以不填可选参数。…

1 - 线程池的基础用法

参考&#xff1a;线程池的基本用法 - 简书 1、为什么要用线程池&#xff1f; 在java中&#xff0c;开启线程的方式一般分为以下三种&#xff1a; a. 继承Thread&#xff0c;实现其run方法&#xff1b; b. 实现Runnabler接口&#xff0c;通过Thread来实现线程&#xff1b; …

法的概念与大纲

一、法的概念 法是由国家制定或认可并由国家强制力保证实施的&#xff0c;反映特定物质生活条件所决定的统治阶级意志&#xff0c;以权利和义务为内容&#xff0c;以确认、保护和发展对统治阶级有利的社会关系和社会秩序为目的的规范系统。 二、法的特征 规范性 国家意志性 权…

微信恢复大师花了200多,套路一环接一环!

数据恢复本是一个科技进步的体现&#xff0c;让误操作导致的重要数据可以找回来。但是近年来数据恢复跟诈骗挂钩&#xff0c;数据恢复本是利好的事情&#xff0c;为什么会跟诈骗挂钩。究竟是什么原因呢&#xff1f;最近小编发现&#xff0c;百度推荐词出现&#xff1a;“微信恢…

Neural Network-神经网络算法本质

1. Word2vec~single CBOW算法推导BP word2vec主要实现方式有&#xff1a;skip-gram和CBOW。 CBOW的目的是根据上下文contextual words来预测当前中心词的概率&#xff0c;且上下文所有单词对当前中心词出现的概率影响权重是一样的&#xff0c;如在袋子中取词&#xff0c;取出…

痞子衡嵌入式:国内外串行NOR Flash厂商官网Cross Reference功能使用体验

大家好&#xff0c;我是痞子衡&#xff0c;是正经搞技术的痞子。今天痞子衡给大家讲的是国内外串行NOR Flash厂商官网Cross Reference功能。 串行 NOR Flash 是一个相对发展稳定的市场&#xff0c;目前全球市场约 90% 的份额被中国的三家厂商(Winbond华邦/MXIC旺宏/GigaDevice兆…

Java入门教程(26)——继承

文章目录1.继承的作用2.继承的关键字3.继承的特点4.实例5.instanceof 运算符继承是面向对象三大特征之一&#xff0c;继承可以让我们减少代码量&#xff0c;实现类的复用1.继承的作用 代码复用&#xff0c;更加容易实现类的扩展方便建模 2.继承的关键字 extends&#xff0c;…

网站都变灰了,几行代码可以实现

前言 这两天&#xff0c;我们经常逛的好多网站、app首页都变灰了&#xff0c;原因大家应该都知道了 网站变灰 ①B站 ②爱奇艺 ③ 腾讯视频 ④ csdn ⑤百度 怎么实现的呢&#xff1f; 难道这些网站开发商在网站开发的时候都准备一套灰色主题的UI么&#xff1f; 好奇心…

端水or信仰?ChatGPT“点评”Web3未来

近日&#xff0c;OpenAI发布了人工智能聊天机器人模型 ChatGPT&#xff0c;产品自11月30日发布到现在仅一周时间&#xff0c;就积累了上百万用户&#xff0c;广受大家好评。有人让它写代码&#xff0c;有人拿高考题目考验它&#xff0c;这些“难题”似乎都难不倒它&#xff0c;…

vue3 教程(上)

学 vue3 通过官方文档更详细&#xff0c;不过阅读本博客&#xff0c;可以更容易理解&#xff0c;且帮你速成&#xff01; 官方文档&#xff08;记得将API风格偏好切换为 组合式 否则你学的是vue2&#xff09; https://cn.vuejs.org/guide/introduction.html 学习前的准备 创建…

[synchronized ]关键字详解

目录 1.synchronized 特性 1.1互斥性 1.2内存刷新 1.3可重入 2.Java 标准库中的线程安全类 3.死锁问题 3.1 一个线程,一把锁 3.2 两个线程,两把锁 3.3 多个线程,多把锁 4.死锁的条件 1.synchronized 特性 1.1互斥性 synchronized 关键字会起到互斥效果,当某个线程执…

【C语言】字符串函数(一)

目录 一、strlen函数(计算字符串长度) 1、strlen函数的用途 2、strlen函数的使用 3、strlen函数的模拟实现 二、strcpy函数(字符串拷贝) 1、strcpy函数的用途 2、strcpy函数的使用 3、strcpy函数的模拟实现 三、strcat函数(字符串追加) 1、strcat函数的用途 2、strcat函数的使用…

【JavaSE】接口剩余内容

目录 1、接口使用实例 &#x1f4d5;逐步分析学生数组排序的写法 ✨思路&#xff1a; ✨代码实现 ✨弊端 &#x1f4d5;、改进 改进思路&#xff1a; 代码实现&#xff1a; 2、Cloneable接口和深拷贝 2.1、cloneable接口的作用 2.2、深拷贝和浅拷贝 2.2.1、浅拷贝 …

yum安装openldap2.4.44,并配置增量复制(Delta-syncrepl)环境

本文是在centos7环境下通过yum安装openldap2.4.44&#xff0c;并配置增量复制&#xff08;Delta-syncrepl&#xff09;环境 官网对于增量复制介绍&#xff1a;https://www.openldap.org/doc/admin24/replication.html#Delta-syncrepl%20replication Delta-syncrepl 是 syncrep…

ADI Blackfin DSP处理器-BF533的开发详解3:GPIO(含源代码)

我们从最基础的GPIO开始&#xff0c;先讲外设&#xff0c;这玩意不管是单片机&#xff0c;还是ARM&#xff0c;又或是FPGA&#xff0c;甚至SOC的芯片&#xff0c;都有GPIO&#xff0c;有共性&#xff0c;就好理解&#xff0c;让我们看看在ADI的DSP里头&#xff0c;GPIO是怎么一…

MySQL数据库学习(2)

一.MySQL语法书写规范&#xff1a; (1).SQL语句要以分号;结尾 在 RDBMS(关系型数据库)当中&#xff0c;SQL语句是逐条执行的&#xff0c;一条 SQL语句代表着数据库的一个操作。SQL语句是使用英文分号;结尾。 (2).SQL语句不区分大小写 SQL不区分关键字的大小写。例如&#xff0c…

CentOS7下mysql主从复制搭建

mysql安装 CentOS7安装MySql5.7完整教程_长头发的程序猿的博客-CSDN博客_centos7 mysql5.7安装 1、配置主机 1.1、修改my.cnf配置文件 vim /etc/my.cnf 最后一行添加&#xff1a; #主服务器唯一ID server-id1 #启用二进制日志 log-binmysql-bin #设置不要复制的数据库(可…