【mybatis】缓存

news2024/12/17 0:56:14

目录

1. mybatis的运行

1.1 引言

1.2 具体运行: 

1.3 sqlSession

介绍local catch

2. 缓存

2.1 概念

 2.2 使用缓存的原因

2.3 什么样的数据能使用缓存

3.  Mybatis缓存

 3.1 一级缓存

3.1.1 测试一级缓存

3.1.2  缓存失效的四种情况

$1 sqlSession不同

$2  sqlSession相同,查询条件不同

$3  sqlSession相同,两次查询之间执行了增删改操作

$4 sqlSession相同,手动清除一级缓存

3.2 二级缓存

3.2.1 二级缓存开启的条件

3.2.2 二级缓存失效的情况

3.2.3 开启二级缓存

3.2.4 分析 

 3.2.5 重要结论

 3.3 Catch参数的具体细节

4. Mybatis缓存查询顺序


1. mybatis的运行

1.1 引言

        当我们想运行这个selectUser,运行之前有@Before@After, 在执行方法 之前  之后  运行(  init()在执行方法之前执行,selectUser()方法执行,destroy()在执行方法之后执行)。

@Before  //前置通知, 在方法执行之前执行
    public void init() throws IOException {
        //加载主配置文件,目的是为了构建SqlSessionFactory对象
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //通过SqlSessionFactory工厂对象创建SqlSesssion对象
        session = factory.openSession();
        //通过Session创建UserDao接口代理对象
        mapper = session.getMapper(UserDao.class);
    }

    @After  //@After: 后置通知, 在方法执行之后执行 。
    public void destory() throws IOException {
        //释放资源
        session.close();
        in.close();
    }

1.2 具体运行: 

        ①。首先,是sqlMapConfig文件,配置信息,所以第一步,读取sqlMapConfig配置文件

-- sqlMapConfig文件里有sql配置文件,以及关于数据库mybatis的配置信息(数据库:用户名,密码以及连接的url,mybatis配置信息中有是否开启懒加载,开启日志)。

       ②。 下一步,生成SqlSessionFactory对象,对象类型是SqlSessionFactory。

       ③。 又生成session对象,对象类型是sqlsession。(整个程序的执行也就到sqlsession,sqlsession是用来干活的)

        ④。通过session调用getMapper创建代理对象。(这里不做过多阐述)

1.3 sqlSession

sqlsession会执行sql语句

        Executor:执行器就是执行程序的,执行sql语句,所有的增删改查。

对象是堆里面的一块内存空间。

 


介绍local catch

        比如

                要对数据库进行查询:select * from A

        因为真正执行的是sqlsession,用sqlsession对他进行查询,查询到的数据会缓存到local catch本地缓存中,下一次再查询,就不用查询数据库了,直接从本地缓存中拿取。

<select id="FindStudentById" parameterType="int" resultType="com.qcby.entity.Student">
    select * from student where id=#{id}
</select>
Student FindStudentById(int id);

$1. 首次进行: 

@Test
    public void FindStudentById(){
        mapper.FindStudentById(1);
    }

结果:

$2. 执行两次:

    @Test
    public void FindStudentById(){
        mapper.FindStudentById(1);
        mapper.FindStudentById(1);
    }

结果:

执行两次查询,但是sql语句只执行一次。

为什么?

        因为第二次查询从本地缓存查数据。

 

@Test
public void FindStudentById1() {
    Student student1=mapper.FindStudentById(1);
    Student student2=mapper.FindStudentById(1);
    System.out.println(student2==student1);
}

   注!!

             值是true, 表明指向的是同一个地址空间,指向的是同一个对象。

这里只执行一次的sql语句与一级缓存有关,也叫sqlSession级别的缓存。


2. 缓存

2.1 概念

  • 存储在内存当中的数据
  • 将用户常使用的数据存放在缓存(内存)当中,用户查询数据就不用从磁盘(关系型数据库文件)当中查询,从缓存当中查询,从而提高查询效率,解决了高并发系统的性能问题

 2.2 使用缓存的原因

        减少和数据库的交互次数,减少系统开销,提高系统效率。

2.3 什么样的数据能使用缓存

        经常查询并且不常改变的数据。


3.  Mybatis缓存

        mybatis包含了一个非常强大的查询缓存特性,他可以非常方便的定制和配置缓存。缓存可以极大的提高查询的效率

        mybatis系统当中默认定义了两级缓存:一级缓存二级缓存

  • 默认情况之下,只有一级缓存开启(sqlSession级别的缓存)
  • 二级缓存需要手动开启配置,需要局域namespace级别的缓存。

 3.1 一级缓存

一级缓存也叫本地缓存

        与数据库同一次会话期间查询到的数据会放入的本地缓存当中。

        如果以后需要获取相同的数据直接去缓存当中拿,没必要再去查询数据库。


3.1.1 测试一级缓存

public class UserTest {
    private InputStream in = null;
    private SqlSession session = null;
    private UserDao mapper = null;

    /**
     * 测试查询所有的方法
     */
    @Test
    public void findById() throws IOException {
        //加载主配置文件,目的是为了构建SqlSessionFactory对象
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //创建SqlSessionFactory对象
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        //通过SqlSessionFactory工厂对象创建SqlSesssion对象
        session = factory.openSession();
        //通过Session创建UserDao接口代理对象
        mapper = session.getMapper(UserDao.class);

        User user1 = mapper.findById(1);
        System.out.println(user1.toString());
        System.out.println("-----------------");
        User user2 = mapper.findById(1);
        System.out.println(user2.toString());
        System.out.println(user1 == user2);
        //释放资源
        session.close();
        in.close();
    }
}


3.1.2  缓存失效的四种情况

  • sqlSession不同
  • sqlSession相同,查询条件不同
  • sqlSession相同,两次查询之间执行了增删改操作!
  • sqlSession相同,手动清除一级缓存
$1 sqlSession不同

$2  sqlSession相同,查询条件不同

        多次查询不同的情况,不会导致缓存失效。

$3  sqlSession相同,两次查询之间执行了增删改操作

$4 sqlSession相同,手动清除一级缓存


3.2 二级缓存

        二级缓存默认情况下是关闭的。

        想要开启的话,涉及到四个条件。

        二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactroy创建SqlSession查询结果会被缓存;此后若再次执行相同的查询语句,结果会从一个缓存中获取。

3.2.1 二级缓存开启的条件

①:在核心配置文件中,设置全局属性caheEnable="true"。

②:在映射件中置

③:查询数据所转换的实体类类型必须实现序列化接口

④:二级缓存必须在SqlSession关闭或提交之后有效

3.2.2 二级缓存失效的情况

        两次查询之间行了任意的增删改,会使得一级二级缓存同时失效。

3.2.3 开启二级缓存

$1 . 在SqlMapConfig.xml配置文件中开启二级缓存

<!‐‐ 开启二级缓存 ‐‐>
<settings>
    <!--开启二级缓存-->
    <setting name="cacheEnabled" value="true"/>
</settings>

$2..  在UserDao.xml配置文件声明使用二级缓存

<!--使用二级缓存-->
<cache/>

$3:  查询数据所转换的实体类类型必须实现序列化接口

public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    // get set方法 .....
 }

$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创建sqlSession
    SqlSession 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();
}

结果:


3.2.4 分析 

$1. 

@Test
public void FindStudentById1() {
    Student student1=mapper1.FindStudentById(1);
    session1.close();//一级缓存失效或提交
    Student student2=mapper1.FindStudentById(1);//这里用的是sqlsession2
    System.out.println(student2==student1);
}

        这样写不对,因为此时session1已经关闭,如果下面继续用session1会报错。

$2. 

@Test
public void FindStudentById1() {
    Student student1=mapper1.FindStudentById(1);
    session1.close();
    Student student2=mapper2.FindStudentById(1);//这里用的是sqlsession2
    System.out.println(student2==student1);
}

        用session2去查询能够命中数据,因为session1查询到的数据提交到了sqlsessionFactory对象中,对象是堆里的 一段内存空间,里有catch,关闭sqlsession1之后,数据会放到sqlSessionFactory当中的catch,当执行sqlsession2时,从catch中取,0.5说明缓存命中率是一半(即存入的sqlSession1结果)。


 3.2.5 重要结论

        打印发现2个对象的地址值不一样,但是确实只发送了一次SQL语句的查询,二级缓存中存储的是数据,不是对象

        一级缓存缓存的是对象,就是查询出的对象,所以前用student1和student2是true,是同一个对象。

 3.3 Catch参数的具体细节

1. eviction(收回策略)--catch满了,回收数据

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

2. flushinterval(刷新间隔) 可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。

  • 默认情况不设置,即没有刷新间隔,缓存仅仅在调用语句时刷新。

原因

        数据库里的数据和缓存里的数据保持一致,故要间隔一段时间取访问数据库。

3. size(引用数目)--缓存的大小

  • 可以被设置为任意正整数,要记住缓存的对象数目和运行环境的可用内存资源数目。默认值是1024 。

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

    • true:只读缓存:会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改, 这提供了很重要的性能优势。
    • false读写缓存: 通过序列化返回缓存对象的拷贝,这种方式会慢一些,但是安全,因此默认是 false。

配置结果

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

4. Mybatis缓存查询顺序

先查询二级缓存,因为二级缓存中可能会有其他程序查询出来的数据,可以直接拿来使用

如果二级缓存未命中,再查询一级缓存

如果一级缓存也没有命中,则查询数据库

SqlSession关闭之后,一级缓存的数据会写入二级缓存

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

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

相关文章

ElasticSearch - 理解doc Values与Inverted Index倒排索引

文章目录 概述倒排索引&#xff1a;从图书馆的索引卡片谈起倒排索引的工作原理 docValues&#xff1a;从数据库的列式存储说起docValues的工作原理 docValues与倒排索引的对比两者的联系&#xff1a;组合使用&#xff0c;优化搜索与分析 小结 概述 在使用 Elasticsearch 进行大…

Python | 数据可视化中常见的4种标注及示例

在Python的数据可视化中&#xff0c;标注&#xff08;Annotation&#xff09;技术是一种非常有用的工具&#xff0c;它可以帮助用户更准确地解释图表中的数据和模式。在本文中&#xff0c;将带您了解使用Python实现数据可视化时应该了解的4种标注。 常见的标注方式 文本标注箭…

【原生js案例】如何实现一个穿透字体颜色的导航

普通的导航大家都会做&#xff0c;像这种穿透字体的导航应该很少见吧。高亮不是通过单独设置一个active类来设置字体高亮颜色&#xff0c;鼠标滑过导航项&#xff0c;字体可以部分是黑色&#xff0c;不分是白色&#xff0c;这种效果的实现 感兴趣的可以关注下我的系列课程【we…

前端中图标的使用

1 antd 使用inconfont.cn中的图标 <template><div class"icons-list"><icon-font type"icon-tuichu" /><icon-font type"icon-facebook" /><icon-font type"icon-twitter" /></div> </templ…

回归预测 | MATLAB实现CNN-BiGRU卷积神经网络结合双向门控循环单元多输入单输出回归预测

回归预测 | MATLAB实现CNN-BiGRU卷积神经网络结合双向门控循环单元多输入单输出回归预测 目录 回归预测 | MATLAB实现CNN-BiGRU卷积神经网络结合双向门控循环单元多输入单输出回归预测预测效果基本介绍程序设计参考资料预测效果 基本介绍 CNN-BiGRU,即卷积神经网络(CNN)与双…

医学分割数据集B超图片肝脏分割数据集labelme格式271张1类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;271 标注数量(json文件个数)&#xff1a;271 标注类别数&#xff1a;1 标注类别名称:["liver"] 每个类别标注的框数&#xf…

【目标检查】YOLO系列之:Triton 推理服务器Ultralytics YOLO11

Triton 推理服务器 1、引言2、Triton服务器2.1 什么是Triton Inference Server2.2 将YOLO11 导出为ONNX 格式2.3 设置Triton 模型库2.3.1 创建目录结构2.3.2 将导出的ONNX 模型移至Triton 资源库 2.4 运行Triton 推断服务器2.4.1 使用 Docker 运行Triton Inference Server2.4.2…

论文学习——多种变化环境下基于多种群进化的动态约束多目标优化

论文题目&#xff1a;Multipopulation Evolution-Based Dynamic Constrained Multiobjective Optimization Under Diverse Changing Environments 多种变化环境下基于多种群进化的动态约束多目标优化&#xff08;Qingda Chen , Member, IEEE, Jinliang Ding , Senior Member, …

【C++】判断能否被 3, 5, 7 整除问题解析与优化

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目描述&#x1f4af;老师代码实现与分析老师代码逻辑分析优点缺点 &#x1f4af;学生代码实现与分析学生代码逻辑分析优点缺点 &#x1f4af;改进与优化优化代码实现优化…

【构建工具】现代开发的重要角色

你可能有所听闻构建工具&#xff0c;但是不知道是干什么的&#xff0c;或者是开发中用到了&#xff0c;大概会使用&#xff0c;但是想理解一下具体的工作原理等&#xff0c;那么我将分享一下我对其的理解。【 我将分为两篇来讲解】。 当我们谈到构建工具时&#xff0c;可以把它…

npm或yarn包配置地址源

三种方法 1.配置.npmrc 文件 在更目录新增.npmrc文件 然后写入需要访问的包的地址 2.直接yarn.lock文件里面修改地址 简单粗暴 3.yarn install 的时候添加参数 设置包的仓库地址 yarn config set registry https://registry.yarnpkg.com 安装&#xff1a;yarn install 注意…

Unity集成Wwise并进行开发

1. 背景 项目要接入WWise&#xff0c;学习一下 1.1 与Unity自带音频系统的区别 Unity有自己的原生音乐功能&#xff1a;AduioSound。但是这个功能较为简单&#xff0c;对于音效开发人员来说并不是很友好。在一些大型的游戏中&#xff0c;音效会接入Wwise这个软件。音效开发者…

【AI知识】有监督学习之回归任务(附线性回归代码及可视化)

1. 回归的基本概念 在机器学习的有监督学习中&#xff0c;回归&#xff08;Regression&#xff09;是一种常见的任务&#xff0c;它的目标是通过观察数据来建立一个模型&#xff0c;用一个或多个自变量来预测因变量的值。 回归分析通常用于&#xff1a; a.预测&#xff0c;基于…

C语言专题之宏的基本概念

合理使用宏可以使我们的代码更加简单&#xff0c;接下来小编就来讲解宏的基本概念&#xff01; 一、宏的定义 宏定义是C/C语言中一项强大而灵活的特性&#xff0c;它允许程序员使用预处理器指令来创建简化的代码表示。这种机制不仅提高了代码的可读性和可维护性&#xff0c;还…

MySQL 复合查询(重点)

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 MySQL 复合查询&#xff08;重点&#xff09; 收录于专栏[MySQL] 本专栏旨在分享学习MySQL的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; …

WPF 控件

<div id"content_views" class"htmledit_views"><p id"main-toc"><strong>目录</strong></p> WPF基础控件 按钮控件&#xff1a; Button:按钮 RepeatButton:长按按钮 RadioButton:单选按钮 数据显示控件 Te…

Docker方式安装人人影视离线完整安装包

本文软件由网友 ルリデ 推荐&#xff1b; 上周&#xff0c;人人影视创始人宣布将人人影视二十年字幕数据开源分享 目前提供了两种使用方式&#xff1a; “在线应用” &#xff1a;意味着需要有互联网才可以使用。官方提供了网站&#xff1a;https://yyets.click “离线使用” …

opencv——(图像梯度处理、图像边缘化检测、图像轮廓查找和绘制、透视变换、举例轮廓的外接边界框)

一、图像梯度处理 1 图像边缘提取 cv2.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]]) 功能&#xff1a;用于对图像进行卷积操作。卷积是图像处理中的一个基本操作&#xff0c;它通过一个称为卷积核&#xff08;或滤波器&#xff09;的小矩阵在图像上…

物联网安全-ARMv8-M Trustzone 实操

前言 本文针对ARMv8m架构M23/M33 MCU安全特性使用进行介绍,以nxp LPC55xx系列和STM32L5xx系列为例,为大家阐述如何使用Trustzone技术提高物联网设备安全性,适合有一定平台安全基础的物联网设备开发人员、安全方案开发人员。 背景 为了提升平台安全性,ARM推出了ARMv8m架构…

深入理解偏向锁、轻量级锁、重量级锁

一、对象结构和锁状态 synchronized关键字是java中的内置锁实现&#xff0c;内置锁实际上就是个任意对象&#xff0c;其内存结构如下图所示 其中&#xff0c;Mark Word字段在64位虚拟机下占64bit长度&#xff0c;其结构如下所示 可以看到Mark Word字段有个很重要的作用就是记录…