【MyBatis】| MyBatis的缓存

news2025/1/16 3:39:04

目录

一:MyBatis的缓存

1. ⼀级缓存

2. ⼆级缓存

3. MyBatis集成第三方缓存EhCache(了解)


一:MyBatis的缓存

(1)缓存(cache):提前把数据存放到缓存当中,下一次使用的时候,直接从缓存中拿。 

(2)缓存的作⽤:通过减少IO的⽅式,来提⾼程序的执⾏效率。

(3)MyBatis的缓存:将select语句的查询结果放到缓存(内存)当中,下⼀次还是这条相同select语句的话,直接从缓存中取,不再查数据库。⼀⽅⾯是减少了IO,另⼀⽅⾯不再执⾏繁琐的查找算法;效率⼤⼤提 升。

(4)mybatis缓存包括:

① ⼀级缓存:将查询到的数据存储到SqlSession中。

② ⼆级缓存:将查询到的数据存储到SqlSessionFactory中。

③或者集成其它第三⽅的缓存:⽐如EhCache【Java语⾔开发的】、Memcache【C语⾔开发的】 等。

注:缓存只针对于DQL语句,也就是说缓存机制只对应select语句。

前期准备

1. ⼀级缓存

①一级缓存的范围是SqlSession。

②⼀级缓存默认是开启的,不需要做任何配置。

③原理:只要使⽤同⼀个SqlSession对象执⾏同⼀条SQL语句,就会⾛缓存。

(1)三兄弟之一:CarMapper接口,编写抽象方法

package com.bjpowernode.mybatis.mapper;

import com.bjpowernode.mybatis.pojo.Car;

public interface CarMapper {
    // 一级缓存:根据id查询信息
    Car selectById(Long id);
}

(2)三兄弟之二:CarMapper.xml文件,编写sql语句

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.bjpowernode.mybatis.mapper.CarMapper">
    <select id="selectById" resultType="Car">
        select * from t_car where id = #{id}
    </select>
</mapper>

(3)三兄弟之三:CarMappeTest类,用来编写测试类

第一种:使用同一个SqlSession对象,重新获取代理对象mapper,访问同一个DQL语句

package com.bjpowernode.mybatis.test;

import com.bjpowernode.mybatis.mapper.CarMapper;
import com.bjpowernode.mybatis.pojo.Car;
import com.bjpowernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

public class CarMapperTest {
    @Test
    public void testSelectById(){
        SqlSession sqlSession = SqlSessionUtil.openSession();
        CarMapper mapper1 = sqlSession.getMapper(CarMapper.class);
        Car car1 = mapper1.selectById(34L);
        System.out.println(car1);
        // 使用同一个sqlSession对象,再次访问同样的SQL语句
        CarMapper mapper2 = sqlSession.getMapper(CarMapper.class);
        Car car2 = mapper1.selectById(34L);
        System.out.println(car2);

        sqlSession.close();
    }
}

执行结果:

从图中可以看出,虽然我们访问了两次同一条DQL语句,但实际上值访问一次数据库,第二次就直接输出了,并没有执行DQL语句!

第二种:使用不同的sqlSession对象,访问同一条DQL语句

注:不能使用封装的SqlSessionUtil工具类了,因为工具类中使用了ThreadLocal

package com.bjpowernode.mybatis.test;

import com.bjpowernode.mybatis.mapper.CarMapper;
import com.bjpowernode.mybatis.pojo.Car;
import com.bjpowernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

public class CarMapperTest {
    @Test
    public void testSelectById() throws Exception{
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        // 创建两个不同的sqlSession对象
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();

        CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
        Car car1 = mapper1.selectById(34L);
        System.out.println(car1);
        // 使用不同的sqlSession对象,再次访问同样的SQL语句
        CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);
        Car car2 = mapper2.selectById(34L);
        System.out.println(car2);
    }
}

执行结果:

从图中可以看出,我们使用不同的sqlSession对象,虽然访问的是同一条DQL语句,但是两条DQL语句都执行了!

(4)什么时候不走缓存?

第⼀种:不同的SqlSession对象。

第⼆种:查询条件变化了。

(5)什么时候缓存失效?

⼀级缓存失效情况包括两种:

①一:第⼀次查询和第⼆次查询之间,执行了clearCache()方法,⼿动清空了⼀级缓存。

②二:第⼀次查询和第⼆次查询之间,执⾏了增删改操作。

注:这个增删改和哪张表没有关系,只要有insert delete update操作,⼀级缓存就失效。

2. ⼆级缓存

(1)⼆级缓存的范围是SqlSessionFactory对象。

(2)使⽤⼆级缓存需要具备以下⼏个条件:

①<setting name="cacheEnabled" value="true"> 全局性地开启或关闭所有映射器配置⽂件中已配置的任何缓存。默认就是true,⽆需设置!

②在需要使⽤⼆级缓存的SqlMapper.xml⽂件中添加一个标签:<catche />

③使⽤⼆级缓存的实体类对象必须是可序列化的,也就是必须实现java.io.Serializable接⼝

④SqlSession对象关闭或提交之后,⼀级缓存中的数据才会被写⼊到⼆级缓存当中;此时⼆级缓存才可⽤。

在CarMapper.xml增加catch标签:

 在Car类当中实现java.io.Serializable接⼝:

 关键一步,关闭SqlSession对象:

(1)三兄弟之一:CarMapper接口,编写抽象方法

package com.bjpowernode.mybatis.mapper;

import com.bjpowernode.mybatis.pojo.Car;

public interface CarMapper {
    
    // 测试二级缓存
    Car selectById2(Long id);
}

(2)三兄弟之二:CarMapper.xml文件,编写sql语句

默认情况下,二级缓存机制是开启的,只需要在对应的SqlMapper.xml文件中使用catche标签,用来表示使用二级缓存机制

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.bjpowernode.mybatis.mapper.CarMapper">

    <!--使用catche标签:表示使用二级缓存-->
    <cache/>

    <select id="selectById2" resultType="Car">
        select * from t_car where id = #{id}
    </select>
</mapper>

(3)三兄弟之三:CarMappeTest类,用来编写测试类

只要SqlSession对象调用close方法关闭,⼀级缓存中的数据(sqlSession)才会被写⼊到⼆级缓存(sqlSessionFactory)当中

package com.bjpowernode.mybatis.test;

import com.bjpowernode.mybatis.mapper.CarMapper;
import com.bjpowernode.mybatis.pojo.Car;
import com.bjpowernode.mybatis.utils.SqlSessionUtil;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;


public class CarMapperTest {
  
    @Test
    public void testSelectById2() throws Exception{
        // 这里只有一个sqlSessionFactory对象,二级缓存对应的就是sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));
        // 创建两个不同的sqlSession对象
        SqlSession sqlSession1 = sqlSessionFactory.openSession();
        SqlSession sqlSession2 = sqlSessionFactory.openSession();
        // 拿到对应的代理对象
        CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);
        CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);

        // 这行代码执行结束,会把数据缓存到一级缓存当中(sqlSession1)
        Car car1 = mapper1.selectById2(34L);
        System.out.println(car1);

        // 关键一步:关闭后,才会把数据放到二级缓存sqlSessionFactory
        sqlSession1.close();

        // 这行代码执行结束,会把数据缓存到一级缓存当中(sqlSession2)
        Car car2 = mapper2.selectById2(34L);
        System.out.println(car2);


        sqlSession2.close();

    }
}

(4)⼆级缓存的失效:只要两次查询之间出现了增删改操作,⼆级缓存就会失效。【⼀级缓存也会失效】。

 (5)⼆级缓存的相关配置(了解):

①eviction:指定从缓存中移除某个对象的淘汰算法。(默认采⽤LRU策略)

        a. LRU:Least Recently Used。最近最少使⽤,优先淘汰在间隔时间内使⽤频率最低的对象。(其实还有⼀种淘汰算法LFU,最不常⽤)

        b. FIFO:First In First Out。⼀种先进先出的数据缓存器,先进⼊⼆级缓存的对象最先被淘汰。

        c. SOFT:软引⽤,淘汰软引⽤指向的对象。具体算法和JVM的垃圾回收算法有关。

        d. WEAK:弱引⽤,淘汰弱引⽤指向的对象。具体算法和JVM的垃圾回收算法有关。

②flushInterval:⼆级缓存的刷新时间间隔,单位毫秒(刷新了也会使原来的缓存失效)。如果没有设置,就代表不刷新缓存,只要内存⾜够⼤,⼀ 直会向⼆级缓存中缓存数据,除⾮执⾏了增删改。

③readOnly:

        a. true:多条相同的sql语句执⾏之后返回的对象是共享的同⼀个,性能好。但是多线程并发可能会存在安全问题。

        b. false:多条相同的sql语句执⾏之后返回的对象是副本,调⽤了clone⽅法。性能⼀般,但安全。

④size:设置⼆级缓存中最多可存储的java对象数量。默认值1024。

3. MyBatis集成第三方缓存EhCache(了解)

(1)集成EhCache是为了代替MyBatis⾃带的⼆级缓存,⼀级缓存是⽆法替代的!

(2)mybatis对外提供了接⼝,也可以集成第三⽅的缓存组件;⽐如EhCache、Memcache等。 EhCache是Java写的、Memcache是C语⾔写的,所以mybatis集成EhCache较为常⻅,按照以下步骤操作,就可以完成集成:

第⼀步:在pom.xml配置中引⼊MyBatis整合ehcache的依赖

<!--mybatis集成ehcache的组件-->
<dependency>
 <groupId>org.mybatis.caches</groupId>
 <artifactId>mybatis-ehcache</artifactId>
 <version>1.2.2</version>
</dependency>

<!--注:ehcache需要slf4j的⽇志组件,log4j不好使-->
<dependency>
 <groupId>ch.qos.logback</groupId>
 <artifactId>logback-classic</artifactId>
 <version>1.2.11</version>
 <scope>test</scope>
</dependency>

第⼆步:在类的根路径下(resources)新建echcache.xml⽂件,并提供以下配置信息。

<?xml version="1.0" encoding="UTF-8"?>

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false">
    <!--磁盘存储:将缓存中暂时不使⽤的对象,转移到硬盘,类似于Windows系统的虚拟内存-->
    <diskStore path="e:/ehcache"/>

    <defaultCache eternal="false" maxElementsInMemory="1000" overflowToDisk="false"
                  diskPersistent="false" timeToIdleSeconds="0" timeToLiveSeconds="600"
                  memoryStoreEvictionPolicy="LRU"/>
</ehcache>

第三步:修改CarMapper.xml⽂件中的标签,添加type属性

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.bjpowernode.mybatis.mapper.CarMapper">
    <!--集成EhcacheCache组件-->
    <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
    <select id="selectById2" resultType="Car">
        select * from t_car where id = #{id}
    </select>
</mapper>

第四步:编写测试程序使⽤,代码还是和上面使用二级缓存的测试代码相同,效果展示也是相同的,都是第一次命中率是0.0,第二次命中率是0.5 

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

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

相关文章

谷歌浏览器无法自动更新怎么办

越来越多的小伙伴选择使用谷歌浏览器&#xff0c;近期有小伙伴发现谷歌浏览器突然无法自动升级更新了&#xff0c;这是怎么回事&#xff0c;遇到这种问题应该怎么解决呢&#xff0c;下面小编就给大家详细介绍一下谷歌浏览器无法自动更新的解决方法&#xff0c;大家感兴趣的话就…

「ChatGPT」一夜之间“火爆出圈“【杞人忧天 or 未雨绸缪】

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计学专业大二本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后…

C语言-程序环境和预处理(14.1)

目录 1. 程序的翻译环境和执行环境 2. 详解编译链接 2.1 翻译环境 2.2 编译本身也分为几个阶段 2.2.1 预编译&#xff08;预处理&#xff09; 2.2.2 编译 2.2.3 汇编 2.2.4 链接 2.3 运行环境 写在最后&#xff1a; 1. 程序的翻译环境和执行环境 翻译环境&#xff1…

云借阅图书管理系统的测试项目实践

一、项目启动&#xff0c;介入了解需求二、需求分析三、制定测试方案&#xff08;计划 策略&#xff09;四、测试执行流程五、编写测试用例六、测试执行6.1 环境搭建6.2 准备工作6.3 执行6.4 缺陷管理七、输出测试报告八、版本发布九、项目总结一、项目启动&#xff0c;介入了…

CV【5】:Layer normalization

系列文章目录 Normalization 系列方法&#xff08;一&#xff09;&#xff1a;CV【4】&#xff1a;Batch normalization Normalization 系列方法&#xff08;二&#xff09;&#xff1a;CV【5】&#xff1a;Layer normalization 文章目录系列文章目录前言2. Layer normalizati…

【C++】多态详解

声明&#xff1a; 本节课件中的代码及解释都是在vs2013下的x86程序中&#xff0c;涉及的指针都是4bytes。如果要其他平台下&#xff0c;部分代码需要改动。比如&#xff1a;如果是x64程序&#xff0c;则需要考虑指针是8bytes问题等等 文章目录多态的概念多态的定义及实现多态的…

Javaweb之Http协议andTomcatandServelt的内容~

JavaWeb技术栈&#xff1a; B/S架构;Browser/server:浏览器/服务器架构模式&#xff0c;它的特点是&#xff0c;客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务器端&#xff0c;浏览器只需要请求服务器&#xff0c;获取Web资源&#xff0c;服务器把Web资源发…

2023全球市场份额排名前五的浏览器,国产的为何没上榜

数据研究机构statcounter发布了PC端浏览器在2023年1月份的最新数据统计。Chrome浏览器凭借66.39%的全球份额稳居第一&#xff0c;Edge第二&#xff0c;Safari第三&#xff0c;Firefox第四&#xff0c;Opera第五。不难看出&#xff0c;在浏览器市场全球占有率排名前5中&#xff…

LeetCode 刷题系列 -- 304. 二维区域和检索 - 矩阵不可变

给定一个二维矩阵 matrix&#xff0c;以下类型的多个请求&#xff1a;计算其子矩形范围内元素的总和&#xff0c;该子矩阵的 左上角 为 (row1, col1) &#xff0c;右下角 为 (row2, col2) 。实现 NumMatrix 类&#xff1a;NumMatrix(int[][] matrix) 给定整数矩阵 matrix 进行初…

我去,竟可直接用命令行操作ChatGPT

ChatGPT 确实杀疯了&#xff0c;已经有 1亿 月活用户了&#xff0c;毕竟它真的有智能的样子。 我前些年还开发过智能客服系统&#xff0c;要是早点遇到 ChatGPT&#xff0c;估计可以省了不少事。 我想接下来有许多业务场景都会使用到它&#xff0c;比如教学&#xff0c;内容创…

OpenCV-PyQT项目实战(5)项目案例01图像模糊

欢迎关注『OpenCV-PyQT项目实战 Youcans』系列&#xff0c;持续更新中 OpenCV-PyQT项目实战&#xff08;1&#xff09;安装与环境配置 OpenCV-PyQT项目实战&#xff08;2&#xff09;QtDesigner 和 PyUIC 快速入门 OpenCV-PyQT项目实战&#xff08;3&#xff09;信号与槽机制 …

毫米波雷达人体存在感应营造更智能的生活

毫米波雷达人体存在感应的工作原理基于多普勒效应&#xff0c;精准度高、稳定性强&#xff0c;其可以穿透非金属物质&#xff0c;比如薄木板、衣服、塑料等物质。 科技改变生活&#xff0c;营造更智能化的生活&#xff0c;最重要的是能够对人体存在进行精准检测&#xff0c;人体…

Git多人协同远程开发

1. 李四&#xff08;项目负责人&#xff09;操作步骤 在github中创建远程版本库testgit将基础代码上传⾄testgit远程库远程库中基于main分⽀创建dev分⽀将 githubleaflife/testgit 共享给组员李四继续在基础代码上添加⾃⼰负责的模块内容 2. 张三、王五&#xff08;组员&…

【树和二叉树】数据结构二叉树和树的概念认识

前言&#xff1a;在之前&#xff0c;我们已经把栈和队列的相关概念以及实现的方法进行了学习&#xff0c;今天我们将认识一个新的知识“树”&#xff01;&#xff01;&#xff01; 目录1.树概念及结构1.1树的概念1.2树的结构1.3树的相关概念1.4 树的表示1.5 树在实际中的运用&a…

SpringBoot:拦截器,过滤器,打包与运行

目录 一、拦截器 1、创建实现类实现HandlerInterceptor 接口 2、注册拦截器对象 二、过滤器 拦截器与过滤器区别 三、打包运行windows版&#xff08;jar包&#xff0c;war包&#xff09; 1、打包为jar包 2、打包为 war包 一、拦截器 拦截器(Interceptor )是一种动态拦截…

二叉搜索树——BinarySearchTree

致前行的人&#xff1a; 要努力&#xff0c;但不要着急&#xff0c;繁花锦簇&#xff0c;硕果累累&#xff0c;都需要过程&#xff01; 目录 1.二叉搜索树 1.1二叉搜索树概念 1.2二叉搜索树的操作 1.3二叉搜索树的实现 2.4二叉搜索树的应用 2.5二叉搜索树的性能分析 2.二…

不用U盘 重装系统(别再浪费钱去电脑城装系统了)

不用U盘 重装系统&#xff08;别再浪费钱去电脑城装系统了&#xff09; 首先打开浏览器&#xff0c;搜索MSDN回车&#xff0c;选择第一个网站 点击操作系统 往下拉找到win10专业版 选择&#xff08;business editions&#xff09;和 (x64) 打开迅雷&#xff0c;点击新建&a…

高德地图开发实战案例:使用Loca数据源展示海量点标注(海量点、自定义分类图标、聚合、信息提示、3D控件)

系列文章目录 高德地图开发实战案例:弧线连接线标注高德地图开发智慧社区网格化数据格式产生的无法单击事件的解决方案高德地图进阶开发实战案例(1):webAPI坐标转换和jsAPI批量转换高德地图进阶开发实战案例(2):电子围栏&#xff08;多边形的绘制&#xff09;的展示高德地图进…

与chatGPT的第一次亲密接触

最近&#xff0c;chatGPT火了&#xff0c;不管传统媒体&#xff0c;还是各种自媒体平台都在说它。今天我突然也想注册一个玩玩&#xff0c;注册前2步还行&#xff0c;但是等点开邮箱校验时&#xff0c;打开网页显示&#xff1a; 上网查了一下&#xff0c;没向中国开放服务&…

Java高手速成 | 对象-关系的映射、映射对象标识符与JPA API的级联操作

01、对象-关系的映射概念 Java对象和关系数据库存在一些简单的映射关系&#xff0c;比如Customer类与CUSTOMERS表映射&#xff0c;一个Customer对象与CUSTOMERS表中的一条记录映射&#xff0c;Customer类的name属性与CUSTOMERS表的NAME字段映射。 但是&#xff0c;毕竟对象模型…