当前位置: 首页 > news >正文

Java课题笔记~ MyBatis缓存

为了减少重复查询给数据库带来的压力,MyBatis提供了缓存机制,这种机制能够缓存查询的结果,避免重复的查询。

MyBatis提供了两种缓存方式:

一种为针对于SqlSession的缓存【默认开启】

另一种为针对于全局的缓存【手动开启】

一级缓存存在SqlSession对象中;二级缓存横跨全部的SqlSession,对所有的查询都生效。

 

一、一级缓存(本地缓存)

在没有配置的情况下,MyBatis默认开启一级缓存

在实际开发时,使用同一个SqlSession对象调用同一个Mapper方法,往往只执行一次SQL,这是因为,当开启一级缓存时,第一次查询,MyBatis会将查询结果放在缓存中,当再次使用这个SqlSession进行同一个查询时,如果数据库的数据没有被更改,则直接将缓存中的数据返回,不会再次发送SQL到数据库

 

1.用户发送查询请求给MyBatis,MyBatis接收到请求时创建一个SqlSession对象处理本次请求的数据库操作,每个SqlSession对象有对应的执行器,执行器在执行SQL语句时会查询Local Cache中是否存在此查询的缓存,如果不存在,则执行此次查询,并将缓存放到Local Cache中;如果存在,则直接将此次查询的缓存返回。

2.当会话结束,即调用SqlSession的close()方法时,会释放此SqlSession中的所有缓存,并将此SqlSession禁用。如果想要清除缓存中的数据,而不关闭SqlSession对象,可以调用SqlSession的clearCache()方法,此方法会清空该SqlSession一级缓存中的所有内容。除此之外,当SqlSession中执行任何一个DML操作,即增加、删除或更改操作时,都将清空此SqlSession的一级缓存

在MyBatis中,对于两次查询,有以下四个条件来判定它们是否是完全相同的两次查询。 1)传入的statementId是否相同 2)查询时结果集范围是否相同 3)查询的最终SQL语句是否相同 4)传递给Statement的参数是否相同 当这些判断都相同时,认为这两次查询完全相同。

如果想要清除缓存中的数据,而不关闭SqlSession对象,可以调用SqlSession的clearCache()方法,此方法会清空该SqlSession一级缓存中的所有内容。除此之外,当SqlSession中执行任何一个DML操作,即增加、删除或更改操作时,都将清空此SqlSession的一级缓存

演示一级缓存的案例,实现步骤:

1、 添加MyBatis的依赖
    <properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><java.version>1.8</java.version></properties><dependencies><!-- mybatis的依赖 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.6</version></dependency><!-- mysql-connector-java 的依赖 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.6</version></dependency><!-- lombok 的依赖--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version><!--            <scope>provided</scope>--></dependency><!-- junit的依赖 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency></dependencies><build><resources><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource><resource><directory>src/main/resources</directory><includes><include>**/*</include></includes></resource></resources></build>
2、添加MyBatis的核心配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<!--MyBatis的核心配置文件-->
<configuration><properties resource="jdbc.properties" /><settings><!--开启数据库日志检测--><setting name="logImpl" value="STDOUT_LOGGING"/></settings><!--类型别名--><typeAliases><package name="com.ambow.pojo" /></typeAliases><!--配置环境--><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="${driver}"/><property name="url" value="${url}"/><property name="username" value="${username}"/><property name="password" value="${password}"/></dataSource></environment></environments><!--配置映射器--><mappers><!-- 4.将包内的映射器接口实现全部注册为映射器【推荐】 --><package name="com.ambow.dao" /></mappers>
</configuration>

核心配置文件,需要读取的jdbc.properties文件:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc
username=root
password=root
3、创建POJO - 基于Lombok
package com.ambow.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dog {private int id;private String name;private int age;}
4、创建Mapper接口
//DogMapper.java
package com.ambow.dao;import com.ambow.pojo.Dog;public interface DogMapper {Dog selectDog();
}
5、创建Mapper映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!--DogMapper.xml-->
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--MyBatis接口开发,需要修改namespace-->
<mapper namespace="com.ambow.dao.DogMapper"><select id="selectDog" resultType="dog">SELECT * from dog where id = 1</select></mapper>
6、创建MybatisUtil工具类
package com.ambow.util;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 java.io.IOException;
import java.io.InputStream;public class MyBatisUtil {//获取SqlSessionpublic static SqlSession getSqlSesssion(){//获取SqlSessionString resource = "mybatis-config.xml";InputStream inputStream = null;try {inputStream = Resources.getResourceAsStream(resource);} catch (IOException e) {e.printStackTrace();}//获取SqlSessionFactory - 工厂对象SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//        System.out.println(sqlSessionFactory);//获取SqlSession - 连接对象SqlSession sqlSession = sqlSessionFactory.openSession();return sqlSession;}//关闭SqlSessionpublic static void closeSqlSession(SqlSession session){if (session != null) {session.close();}}}
7、测试一级缓存
package com.ambow.test;import com.ambow.dao.DogMapper;
import com.ambow.pojo.Dog;
import com.ambow.util.MyBatisUtil;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;public class CacheTest {/*一级缓存:SqlSession级别的缓存,也就是说,同一个SqlSession共用一个缓存对象*/@Testpublic void test01(){//获取SqlSessionSqlSession sqlSesssion01 = MyBatisUtil.getSqlSesssion();//第一次查询 - id为1DogMapper dogMapper01 = sqlSesssion01.getMapper(DogMapper.class);Dog dog1 = dogMapper01.selectDog();System.out.println(dog1);//第二次查询 - id为1DogMapper dogMapper02 = sqlSesssion01.getMapper(DogMapper.class);Dog dog2 = dogMapper02.selectDog();System.out.println(dog2);}/*一级缓存:两个SqlSession对象,不会共用一个缓存对象*/@Testpublic void test02(){//获取SqlSessionSqlSession sqlSesssion01 = MyBatisUtil.getSqlSesssion();SqlSession sqlSesssion02 = MyBatisUtil.getSqlSesssion();//第一次查询 - id为1DogMapper dogMapper01 = sqlSesssion01.getMapper(DogMapper.class);Dog dog1 = dogMapper01.selectDog();System.out.println(dog1);//第二次查询 - id为1DogMapper dogMapper02 = sqlSesssion02.getMapper(DogMapper.class);Dog dog2 = dogMapper02.selectDog();System.out.println(dog2);}/*一级缓存:SqlSession调用close()方法,缓存会被释放*/@Testpublic void test03(){//获取SqlSessionSqlSession sqlSesssion01 = MyBatisUtil.getSqlSesssion();//第一次查询 - id为1DogMapper dogMapper01 = sqlSesssion01.getMapper(DogMapper.class);Dog dog1 = dogMapper01.selectDog();System.out.println(dog1);sqlSesssion01.close();//第二次查询 - id为1DogMapper dogMapper02 = sqlSesssion01.getMapper(DogMapper.class);Dog dog2 = dogMapper02.selectDog();System.out.println(dog2);}/*一级缓存:调用SqlSession的clearCache()方法,可以释放缓存*/@Testpublic void test04(){//获取SqlSessionSqlSession sqlSesssion01 = MyBatisUtil.getSqlSesssion();//第一次查询 - id为1DogMapper dogMapper01 = sqlSesssion01.getMapper(DogMapper.class);Dog dog1 = dogMapper01.selectDog();System.out.println(dog1);//清除缓存sqlSesssion01.clearCache();//第二次查询 - id为1DogMapper dogMapper02 = sqlSesssion01.getMapper(DogMapper.class);Dog dog2 = dogMapper02.selectDog();System.out.println(dog2);}/*一级缓存:当SqlSession中执行任何一个DML操作,即增加、删除或更改操作时,都将清空此SqlSession的一级缓存*/@Testpublic void test05(){//获取SqlSessionSqlSession sqlSesssion01 = MyBatisUtil.getSqlSesssion();//第一次查询 - id为1DogMapper dogMapper01 = sqlSesssion01.getMapper(DogMapper.class);Dog dog1 = dogMapper01.selectDog();System.out.println(dog1);//执行DML操作 - 数据更新int row = dogMapper01.updateDog();System.out.println("执行了更新语句");//第二次查询 - id为1DogMapper dogMapper02 = sqlSesssion01.getMapper(DogMapper.class);Dog dog2 = dogMapper02.selectDog();System.out.println(dog2);}
}

二、二级缓存(全局缓存)

MyBatis的二级缓存是Application级别的缓存,与一级缓存的原理类似。

不同的是,二级缓存的作用域扩大到了每个命名空间,在同一个命名空间中的所有查询都将被缓存。

MyBatis二级缓存的执行流程:

1、MyBatis中的二级缓存默认关闭,需要手动开启,当开启后,用户发送有关数据库操作的请求会被CacheExecutor拦截。

2、CacheExecutor拦截数据库操作后,到Configuration对象中查看对应命名空间中的缓存,如果发现存在相同查询的缓存,则直接返回该缓存;如果不存在,则进入一级缓存中查找。

即先经过二级缓存查找后,再从一级缓存中寻找。

MyBatis在执行到DML语句时,会清空当前命名空间中所有的缓存。此外,MyBatis开启二级缓存后可能会有脏读问题:按照开发规范,每个类都有自己的命名空间,命名空间不允许有针对其他类的更改,但如果在B类的命名空间中对A类做出更改时,B类命名空间中的二级缓存将会被清除,A类中的缓存不会被清除,当A类命名空间中有针对于A类的查询操作时,就会寻找二级缓存中的旧数据并将其返回。  

演示案例

演示1:不开启二级缓存,一级缓存无法实现跨SqlSession之间的缓存。

演示2:开启二级缓存,可以实现跨SqlSession的缓存。

<!--设置 --><settings><!--缓存二级配置的全局开关--><setting name="cacheEnabled" value="true" /><!--开启数据库日志检测--><setting name="logImpl" value="STDOUT_LOGGING"/></settings>

使用MyBatis的二级缓存,需要以下几步:

  1. 在主配置文件中开启全局二级缓存配置

    <setting name="cacheEnabled" value="true">

  2. 在映射文件中加入<cache />标签

  3. 对应的pojo需要实现序列化

  4. 注意:测试二级缓存需要commit提交,如果不提交是不会保存到二级缓存的

演示3:执行DML操作后,二级缓存会清空。

演示4:在不规范开发时,二级缓存会出现脏读情况。

  • 按照开发规范,每个类都有自己的命名空间,命名空间不允许有针对其他类的更改,但如果在B类的命名空间中对A类做出更改时,B类命名空间中的二级缓存将会被清除,A类中的缓存不会被清除,当A类命名空间中有针对于A类的查询操作时,就会寻找二级缓存中的旧数据并将其返回。

相关文章:

Java课题笔记~ MyBatis缓存

为了减少重复查询给数据库带来的压力&#xff0c;MyBatis提供了缓存机制&#xff0c;这种机制能够缓存查询的结果&#xff0c;避免重复的查询。 MyBatis提供了两种缓存方式&#xff1a; 一种为针对于SqlSession的缓存【默认开启】 另一种为针对于全局的缓存【手动开启】 一…...

数据结构--循环队列、链队

基础知识 //循环队列数据结构 typedef struct { QElemType data[MaxQSize];//数据域 int front,rear; //队头队尾指针 }SqQueue; //链队结点数据结构 typedef struct QNode { int data;//数据域 struct QNode* next;//指针域 }QNode, * QueuePtr; typedef struct { struct Q…...

hbuilderx主题色分享-github风格

效果 步骤 hbuilderx总共有三种主题&#xff0c;绿柔主题Default,酷黑主题Monokai,雅黑主题Atom One Dark,修改主题色是基于三种主题之一的&#xff0c;不能直接创建一个新主题&#xff0c;比如下方配置是基于Atom One Dark(对象名为[Atom One Dark])&#xff0c;则当前hbuild…...

【C++】类与对象(1)

文章目录 前言一、什么是类1.类的定义2.类的访问限定符3.类的作用域 二、类的实例化三、类对象的存储方式四、this指针总结 前言 C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解问题的步骤&#xff0c;通过函数调用逐步解决问题。C是基于面向对象的&#x…...

Java课题笔记~ MyBatis核心配置

一、核心配置文件概览 MyBatis配置文件中有MyBatis框架的核心配置&#xff0c;负责对MyBatis进行全局管理。它包含许多控制MyBatis功能的重要元素。 <configuration><!--设置配置文件--><properties><property name"" value""/>…...

从0开始自学网络安全(黑客)

前言 黑客技能是一项非常复杂和专业的技能&#xff0c;需要广泛的计算机知识和网络安全知识。你可以参考下面一些学习步骤&#xff0c;系统自学网络安全。 在学习之前&#xff0c;要给自己定一个目标或者思考一下要达到一个什么样的水平&#xff0c;是学完找工作&#xff08;…...

kotlin 编写一个简单的天气预报app(四)增加界面显示

编写界面来显示返回的数据 用户友好性&#xff1a;通过界面设计和用户体验优化&#xff0c;可以使天气信息更易读、易理解和易操作。有效的界面设计可以提高用户满意度并提供更好的交互体验。 增加城市名字的TextView <TextViewandroid:id"id/textViewCityName"…...

英语不好能学好Python吗?Python常用英文单词汇总

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 有些小可爱对英语好不好对学习python有没有什么影响有着很深的疑惑。 其实python学习&#xff0c;主要靠多敲多练&#xff0c;主打一个熟能生巧 那今天我就给大家带来Python常用英文单词汇总&#xff0c; 新手期小可…...

Counting Stars 2023“钉耙编程”中国大学生算法设计超级联赛(5)hdu7335

Problem - 7335 题目大意&#xff1a;如果一个点连接着k个点&#xff0c;就称这k1个点构成k星图&#xff0c;现给出一个大小为n的图&#xff0c;问2星图的数量^3星图的数量^...^n星图的数量是多少 3<n<1e6;1<m<1e6 思路&#xff1a;因为边数总共不超过1e6&#…...

浅谈document.write()输出样式

浅谈document.write()输出样式 js中的最基本的命令之一&#xff1a;document.write&#xff08;&#xff09;&#xff0c;用于简单的打印内容到页面上&#xff0c;可以逐字打印你需要的内容——document.write("content"),这里content就是需要输出的内容&#xff1b;…...

AIGC(Artificial Intelligence and Graph Computing)职业发展路径和前景如何?

目录 一、AIGC 基本概念二、AIGC 市场规模三、AIGC 未来发展前景四、AIGC 职业发展路径五、AIGC 技能要求六、AIGC 相关公司 AIGC&#xff08;Artificial Intelligence and Graph Computing&#xff09;是人工智能和图计算的结合&#xff0c;它是一种用于处理大规模复杂数据的计…...

MySql006——基本的SELECT查询语句

在《MySql003——结构化查询语言SQL基础知识》中&#xff0c;我们学习了有关SQL的基础知识&#xff0c;也知道SQL中查询语句SELECT使用最为频繁 接下来我们将学习一些基本的SELECT查询语句 一、SELECT语句的通用语法 在MySQL数据库中&#xff0c;使用SELECT语句可以查询数据…...

【啥都生】分类项目中的模型搭建代码解析

def build_model(cfg):if isinstance(cfg, list):modules [eval(cfg_.pop("type"))(**cfg_) for cfg_ in cfg]return Sequential(*modules)else:return eval(cfg.pop("type"))(**cfg)b站up啥都生维护的分类项目 这段代码的功能是完成模型搭建&#xff0c;…...

Ubuntu出现了内部错误

使用的Ubuntu版本是18.04&#xff0c;使用的时候弹出对话框说出现了内部错误&#xff0c;好奇是哪里出现了错误&#xff0c;查找了一下解决的办法&#xff0c;记录一下。 参考解决方案&#xff1a;ubantu出现了内部错误 一旦程序崩溃过一次&#xff0c;就会生成一个.crash文件…...

Stable Diffusion AI绘画初学者指南【概述、云端环境搭建】

概述、云端环境搭建 Stable Diffusion 是什么、能干啥&#xff1f; 是一种基于深度学习的图像处理技术&#xff0c;可以生成高质量的图像。它可以在不需要真实图像的情况下&#xff0c;通过文字描述来生成逼真的图像。 可以对图像进行修复、超分辨率转换&#xff0c;将低分辨…...

小程序动态隐藏分享按钮

// 禁用分享 wx.hideShareMenu({menus: [shareAppMessage, shareTimeline] })// 显示分享 wx.showShareMenu({withShareTicket: true,menus: [shareAppMessage, shareTimeline] })//私密消息 wx.updateShareMenu({isPrivateMessage: true, })...

语音合成是什么?如何进行语音合成TTS数据采集?

我们在上一篇讲到语音数据采集分为常见的两种语音数据采集类型&#xff0c;一个是语音识别数据&#xff08;ASR&#xff09;&#xff0c;另一个是语音合成&#xff08;TTS&#xff09;。这一期中&#xff0c;我们将介绍语音合成技术是什么&#xff0c;如何采集语音合成数据和制…...

实用干货!一文读懂Salesforce中6种数据关系类型!

Salesforce中对象之间的数据关系可能是一个棘手的话题。对于创建自定义对象的业务场景&#xff0c;需要决定使用哪些关系类型来扩展Salesforce数据模型。 01 查找关系 查找关系&#xff08;Lookup Relationships&#xff09;是一种松散耦合&#xff08;loosely coupled&…...

Spring引入外部数据源

spring-dataSource.xml 数据源配置文件 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns:context"h…...

word里的页码问题

封面不需要页码怎么办 一份文档写完&#xff0c;如果需要页码&#xff0c;第一页是封面&#xff0c;封面不需要页码怎么办&#xff1f; 解决&#xff1a;打开页眉页脚&#xff0c;然后把首页不同勾选上&#xff0c;这一页就没有页码了。 目录页与正文页码格式不同怎么办 目录…...

​LeetCode解法汇总142. 环形链表 II

目录链接&#xff1a; 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目&#xff1a; https://github.com/September26/java-algorithms 原题链接&#xff1a; 力扣 描述&#xff1a; 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如…...

危化品行业防雷检测综合解决方案

危化品是指具有毒害、腐蚀、爆炸、燃烧、助燃等性质&#xff0c;能够对人体、设施或者环境造成危害的化学品。危化品的生产、储存、运输、使用等过程中&#xff0c;都存在着遭受雷击引发火灾或者爆炸事故的风险。因此&#xff0c;对危化品场所进行防雷检测&#xff0c;是保障危…...

刷题笔记:day 1

力扣 283 移动零 解法一&#xff1a;双指针 定义一个指针 cur 去遍历数组 &#xff1b; 定义一个指针 dest 去指向已处理区间中&#xff0c;非零的最后一个位置。 然后让 指针 cur 遇到 0 &#xff0c;就往后走 &#xff1b; 遇到的数不是 0 &#xff0c;就与 dest指针的下…...

Linux——平台设备及其驱动

目录 前言 一、平台设备 二、平台驱动 三、平台驱动简单实例 四、 电源管理 五、udev 和驱动的自动加载 六、使用平台设备的LED 驱动 七、自动创建设备节点 前言 要满足 Linux 设备模型&#xff0c;就必须有总线、设备和驱动。但是有的设备并没有对应的物理总线&#x…...

【C语言技巧】三种多组输入的写法

文章目录 第一种&#xff1a;直接与1判断第二种&#xff1a;与EOF判断第三种&#xff1a;巧用按位取反符号“~”写在最后 在代码的实际运用中&#xff0c;我们经常会遇到需要多组输入的情况&#xff0c;那么今天博主就带大家一起盘点三种常见的多组输入的写法 第一种&#xff1…...

DB2数据库巡检脚本

DB2数据库巡检脚本的示例&#xff1a; #!/bin/bash# 设置DB2登录凭证 DB2_USER"your_username" DB2_PASSWORD"your_password"# 设置巡检结果输出文件路径 OUTPUT_FILE"/path/to/output.log"# 获取DB2版本信息 version_info$(db2 connect to you…...

Eureka 学习笔记3:EurekaHttpClient

版本 awsVersion ‘1.11.277’ EurekaTransport 用于客户端和服务端之间进行通信&#xff0c;封装了以下接口的实现&#xff1a; ClosableResolver 接口实现TransportClientFactory 接口实现EurekaHttpClient 接口实现及其对应的 EurekaHttpClientFactory 接口实现 private …...

Android Framework 之 启动流程

Android 系统的启动流程 Android 系统的启动流程可以分为以下几个主要步骤&#xff1a; 引导加载器&#xff08;Bootloader&#xff09;启动&#xff1a;当你打开一个 Android 设备时&#xff0c;首先启动的是引导加载器。引导加载器负责启动 Android 的核心操作系统。 Linux…...

Qt、C/C++环境中内嵌LUA脚本、实现LUA函数的调用执行

Qt、C/C环境中内嵌LUA脚本、实现LUA函数的调用执行 Chapter1. Qt、C/C环境中内嵌LUA脚本、实现LUA函数的调用执行1、LUA简介2、LUA脚本的解释器和编译器3、C环境中内嵌LUA执行LUA函数调用4、Qt内嵌LUA执行LUA函数调用5、运行结果6、内嵌LUA脚本在实际项目中的案例应用 Chapter1…...

超详细 | 模拟退火算法及其MATLAB实现

模拟退火算法(simulated annealing&#xff0c;SA)是20世纪80年代初期发展起来的一种求解大规模组合优化问题的随机性方法。它以优化问题的求解与物理系统退火过程的相似性为基础&#xff0c;利用Metropolis算法并适当地控制温度的下降过程实现模拟退火&#xff0c;从而达到求解…...