一、缓存机制的原理

计算机每次从mysql中执行sql语句,都是内存与硬盘的通信,对计算机来说,影响效率。

因此使用缓存机制。

 

1-1、MyBatis 的缓存机制:

执行 DQL(select 语句)的时候,将查询结果放到缓存当中(内存当中),如果下一次还是执行完全相同的 DQL(select 语句)语句,直接从缓存中拿数据,不再查数据库了。不再去硬盘上找数据了。

示例:

第一次执行这个 SQL:

select * from t_car where id=1;

第二次还是执行这个 SQL,完全一样:

select * from t_car where id=1;

此时,从缓存中获取,不再查数据库了。

当两条sql语句之间,对数据库做了任何修改操作,缓存将从内存中清除。

目的:提高执行效率。

缓存机制:使用减少 IO 的方式来提高效率。

IO:读文件和写文件。

缓存通常是我们程序开发中优化程序的重要手段:

  • 字符串常量池
  • 整数型常量池
  • 线程池
  • 连接池
  • ……

【小结】:

        缓存(cache)就是内存,提前把数据放到内存中,下一次用的时候,直接从缓存中拿,效率高!

二、几种常见的缓存/池化技术

这些“池”技术,其实都是 Java 中的 缓存/复用机制,目的是:提升性能、减少资源消耗、避免频繁创建和销毁对象。下面来系统讲解几种常见的缓存/池化技术:


2-1、字符串常量池(String Constant Pool)

1、原理:

Java 中字符串是不可变的(final,所以 JVM 会把相同的字符串常量只保留一份副本,存放在一个称为 字符串常量池 的内存区域。

String s1 = "hello";
String s2 = "hello";
System.out.println(s1 == s2); // true
  • "hello" 是一个字符串字面量,保存在常量池中

  • s1 和 s2 都指向同一个地址

2、注意:

String s3 = new String("hello");
System.out.println(s1 == s3); // false(堆 vs 常量池)

如果你想把 new 出来的字符串放入常量池:

String interned = s3.intern();
System.out.println(s1 == interned); // true

 

2-2、整数型常量池(Integer Cache)

1、原理:

Java 对于包装类型 Integer,有一个缓存区[-128, 127]),当你使用 valueOf() 方法创建时,会从缓存中取对象而不是创建新对象。

Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true(缓存)Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false(未缓存)

2、范围:

JVM 默认缓存范围为 [-128, 127],可以通过启动参数修改

-XX:AutoBoxCacheMax=300

2-3、线程池(Thread Pool)

1、原理:

线程的创建与销毁成本高(涉及操作系统资源),频繁创建新线程会拖慢系统。

所以,线程池把线程复用起来,让多个任务共享固定线程,提高并发效率。

2、常用方式:

        // 创建固定大小为 3 的线程池ExecutorService pool = Executors.newFixedThreadPool(3);// 模拟提交 5 个任务for (int i = 1; i <= 15; i++) {int taskId = i;pool.submit(new Runnable() {public void run() {String threadName = Thread.currentThread().getName();System.out.println("任务 " + taskId + " 开始,线程:" + threadName);try {Thread.sleep(20000); // 模拟任务耗时} catch (InterruptedException e) {e.printStackTrace();}System.out.println("任务 " + taskId + " 结束,线程:" + threadName);}});}// 关闭线程池(注意不是立刻关闭)pool.shutdown();

打印结果: 

 

可以看到线程是复用的。

Executors 提供常见线程池工厂方法:

  • newFixedThreadPool(n)

  • newCachedThreadPool()

  • newSingleThreadExecutor()

  • newScheduledThreadPool(n)


2-4、连接池(Connection Pool)

1、 原理:

数据库连接创建代价高(要连接服务器、授权、建会话),所以使用连接池 复用已建立的连接

2、常见实现:

  • HikariCP(Spring Boot 默认)

  • DBCP

  • C3P0

  • Druid

3、示例(Spring Boot):

spring.datasource.hikari.maximum-pool-size: 10

应用启动后,会提前建立 10 个连接,放入连接池,供业务查询复用。


2-5、对象池(Object Pool)

对于那些频繁使用又比较重量级的对象(如:ByteBuffer, Socket, 数据库连接),也可以池化处理。

Java 标准库没有通用的 ObjectPool,但 Apache Commons Pool 提供支持。

GenericObjectPool<MyReusableObject> pool = new GenericObjectPool<>(new MyObjectFactory());MyReusableObject obj = pool.borrowObject(); // 借
obj.doSomething();                          // 用
pool.returnObject(obj);                     // 还

你需要在项目中引入 Apache Commons Pool 的依赖(如果用 Maven):

<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.11.1</version> <!-- 可根据需要换版本 -->
</dependency>

 


2-6、内存缓存(如 LRU 缓存)

Java 中可以自己实现缓存算法(如 LRU),也可以使用:

  • Guava Cache

  • Caffeine(高性能)

  • Ehcache

  • Redis(分布式)

示例(Caffeine):

Cache<String, Object> cache = Caffeine.newBuilder().maximumSize(1000).expireAfterWrite(10, TimeUnit.MINUTES).build();

2-7、类加载缓存(ClassLoader)

JVM 对每个类只加载一次,会将 .class 文件缓存到内存中,后续实例化只需创建对象而不重复加载。


2-8、反射缓存(Method/Field 缓存)

使用反射获取字段/方法(如 Class.getDeclaredMethods())是慢操作。JVM 会自动缓存这些反射结构,Spring、MyBatis 等框架也会自己做缓存。


2-9、JVM 运行时常见缓存(底层)

缓存类型说明
字符串常量池复用 String 常量
Integer 缓存避免频繁装箱创建 Integer
Class 常量池常量值如 final 字段、枚举等
方法句柄缓存JVM 优化调用性能
Lambda 表达式缓存编译后只创建一次匿名类对象

2-10、总结对比表

技术名称类型缓存对象控制方式是否可配置
字符串常量池编译期/运行期String自动/intern()
Integer 缓存运行期Integer自动/valueOf()
线程池并发ThreadExecutors
连接池IO资源DB连接DataSource
ObjectPool自定义业务对象Apache Commons
Guava/Caffeine本地缓存任意对象API构建
Redis分布式缓存任意对象客户端控制

三、Mybatis的缓存

mybatis 缓存包括:

  • 一级缓存:将查询到的数据存储到 SqlSession 中。
  • 二级缓存:将查询到的数据存储到 SqlSessionFactory 中。
  • 集成其它第三方的缓存:比如 EhCache【Java 语言开发的】、Memcache【C 语言开发的】等。

SqlSessionFactory是一个数据库一个,SqlSession作用域是当前的sql会话。

缓存只针对DQL语句,也就是说:缓存只针对select语句!

 

3-1、MyBatis 一级缓存

3-1-1、什么是一级缓存?

一级缓存是 MyBatis 的默认缓存机制,作用范围是 一次 SqlSession 内部。简单说:

同一个 SqlSession 中,相同的查询语句和参数,MyBatis 会从缓存中取数据,不会再次访问数据库

一级缓存mybatis默认开启,不需要任何配置!


3-1-2、一级缓存工作流程图

SqlSession├── 查询语句 1(未命中缓存) → 查数据库,缓存结果├── 查询语句 1(再次执行) → 命中缓存,直接返回└── SqlSession.close() → 缓存销毁

3-1-3、一级缓存使用示例

@Test
public void testFirstLevelCache() {SqlSession session = sqlSessionFactory.openSession();UserMapper mapper = session.getMapper(UserMapper.class);// 第一次查询,去数据库User u1 = mapper.selectById(1L);System.out.println("第一次查询:" + u1);// 第二次查询相同 ID,命中缓存User u2 = mapper.selectById(1L);System.out.println("第二次查询:" + u2);System.out.println(u1 == u2); // true(同一个对象)session.close();
}

【注意】:

此时,控制台只执行一条sql select语句! 


 

3-1-4、哪些情况会导致缓存失效?

  1. SqlSession 不是同一个

    每次 openSession() 创建新的 Session,缓存就不同。

    示例:

        @Testpublic void testFirstCache2() throws IOException {SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));SqlSession sqlSession1 = sqlSessionFactory.openSession();CarMapper mapper1 = sqlSession1.getMapper(CarMapper.class);Car car1 = mapper1.selectOneById(1L);System.out.println(car1);SqlSession sqlSession2 = sqlSessionFactory.openSession();CarMapper mapper2 = sqlSession2.getMapper(CarMapper.class);Car car2 = mapper2.selectOneById(1L);System.out.println(car2);sqlSession1.close();sqlSession2.close();}

    此时,控制台会打印两条sql select语句。

  2. 执行了 update / insert / delete 操作

    写操作会清空缓存(保证数据一致性),修改任意一张表,都会清空缓存!

  3. 手动清空缓存

    session.clearCache();
    
  4. 查询的 SQL 或参数不同


 

3-1-5、一级缓存原理简述

  • MyBatis 内部维护了一个 PerpetualCacheHashMap 实现)

  • 每次查询前会根据 SQL+参数,生成 key,先查缓存

  • 如果命中,直接返回

  • 如果没命中,查数据库并存入缓存

3-2、MyBatis 二级缓存

MyBatis 的二级缓存,这对优化多次查询、减少数据库压力非常重要,尤其是跨 SqlSession 的查询场景


 

3-2-1、什么是二级缓存?

二级缓存是 MyBatis 提供的跨 SqlSession 的缓存机制。

它的作用范围是:Mapper 映射级别(namespace)不同 SqlSession 之间共享缓存数据


3-2-2、一级 vs 二级缓存对比

对比项一级缓存(默认)二级缓存(需开启)
缓存范围单个 SqlSession 内多个 SqlSession 共享
默认状态开启默认关闭
生命周期SqlSession 生命周期应用级、映射器级别
存储结构基于 HashMap(PerpetualCache)可自定义实现
典型用途同一次操作内避免重复查询缓解高频读操作数据库压力

3-2-3、使用二级缓存的三步配置


Step 1:开启全局二级缓存
<settings><setting name="cacheEnabled" value="true"/>
</settings>

【注意】:

是的,<setting name="cacheEnabled" value="true"/> 在 MyBatis 中默认就是开启。 


Step 2:在 Mapper 映射文件中开启 <cache/>

例如:UserMapper.xml

<mapper namespace="com.example.mapper.UserMapper"><cache /><select id="selectById" resultType="User">SELECT * FROM users WHERE id = #{id}</select>
</mapper>
  • 你也可以配置更多参数(见下方扩展)


Step 3:实体类实现 Serializable 接口(因为缓存需要序列化)
public class User implements Serializable {private Long id;private String name;// ...其他字段
}

3-2-4、二级缓存使用示例

示例1:没有使用二级缓存

示例2:数据从二级缓存中获取

sqlSession1关闭,数据保存到二级缓存中,再执行sqlSession2中的select语句,会从二级缓存中获取。

【注意】:

一级缓存的优先级高,先从一级缓存中取数据,若是一级缓存关闭,则从二级中取数据!

 

示例3:跨namespace测试二级缓存

【注意】:

两个mapper不一样,但是执行的select语句和参数都是一样的,但是控制台依旧会执行两条select查询语句,说明二级缓存不能跨namespace!


3-2-5、哪些操作会清空二级缓存?

  • 对该 namespace 进行了 update/insert/delete(增、删、改)

  • 显式调用了 clearCache()

  • 配置 <cache flushInterval="..."/> 自动过期

  • 跨 namespace 无法共享(除非手动自定义)


3-2-6、常见 <cache> 配置项

<cache eviction="LRU"               <!-- 缓存淘汰策略:LRU, FIFO, SOFT, WEAK -->flushInterval="60000"        <!-- 自动刷新间隔:毫秒;刷新后二级缓存失效 -->size="512"                   <!-- 最大缓存对象数量 -->readOnly="false"             <!-- 是否只读(只读更快但不可修改), car1 == car2 -->blocking="true"              <!-- 防止缓存击穿 -->
/>

 

3-2-7、一级缓存 vs 二级缓存(图解理解)

+------------------------+
| SqlSession A           |
|  └── 一级缓存(仅自己用)     |
|                        |
| SqlSession B           |
|  └── 一级缓存(仅自己用)     |
+------------------------+↓(关闭 SqlSession 后)
+------------------------+
|     二级缓存(共享)          |
|     key: SQL + 参数          |
|     value: 查询结果对象      |
+------------------------+

3-3、自定义缓存实现(可选)

MyBatis 允许你自定义二级缓存逻辑(如整合 Redis),也就是集成第三方的缓存组件。

【注意】:

MyBatis的一级缓存是不可替代的!集成第三方的缓存组件,替代的是二级缓存!

MyBatis 如何集成第三方缓存组件,比如 Redis、EhCache、Caffeine 等。这种方式可以将 MyBatis 的二级缓存升级为分布式或高性能缓存,实现更强的可扩展性与性能提升。 

1、示例:集成EhCache 

step1:pom.xml中添加依赖
<!-- MyBatis 对 EhCache 的支持 -->
<dependency><groupId>org.mybatis.caches</groupId><artifactId>mybatis-ehcache</artifactId><version>1.2.1</version>
</dependency>

step2: 添加 ehcache.xml 配置文件
<ehcache><cache name="com.example.mapper.UserMapper"maxEntriesLocalHeap="1000"timeToLiveSeconds="600"/>
</ehcache>

step3: 在对应的xxxMapper.xml 中配置:

step4: 编写测试类

测试类和测试二级缓存一样,没有变动!

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【机器学习深度学习】LoRA 与 QLoRA:大模型高效微调的进阶指南

目录 前言 一、LoRA&#xff1a;低秩微调的经典之作 二、QLoRA&#xff1a;效率与精度的升级版 三、LoRA vs QLoRA&#xff1a;如何选择&#xff1f; 3.1 性能维度对比 3.2 根据「显卡资源」选择 3.3 根据「任务类型与目标」选择 3.4 根据「模型规模」选择 3.5 根据…

教育行业网络升级最佳实践:SD-WAN、传统方案与混合方案对比分析

随着教育行业的数字化转型不断深入&#xff0c;网络的稳定性、灵活性和安全性成为各类教育应用&#xff08;如远程课堂、智慧校园和教育云平台&#xff09;的核心支撑。然而&#xff0c;传统的 MPLS 专线方案成本高、扩展性差&#xff0c;而纯 SD-WAN 的方案在极高可靠性要求的…

[黑马头条]-文章列表加载

目录 1.1)需求分析 1.2)表结构分析 ap_article 文章基本信息表 ap_article_config 文章配置表 ap_article_content 文章内容表 导入文章数据库 实现思路 接口定义 功能实现 定义接口 编写mapper文件 编写业务层代码 实现类&#xff1a; 定义常量类 编写控制器代码 …

使用TIANAI-CAPTCHA进行行为验证码的生成和缓存的二次校验

1.导入依赖&#xff1a;<dependency><groupId>cloud.tianai.captcha</groupId><artifactId>tianai-captcha-springboot-starter</artifactId><version>1.5.2</version> </dependency>2.在application.yml中配置验证码相关配置…

db.refresh()的重复使用和db.rollback()

db.refresh()在 SQLAlchemy 中&#xff0c;db.refresh() 用于从数据库中重新加载对象的状态&#xff0c;确保对象属性与数据库中的实际数据保持一致。下面详细介绍其使用场景和作用&#xff1a;1.获取数据库生成的值当数据库自动生成字段&#xff08;如自增 ID、默认值、触发器…

《Web安全之机器学习入门》读书笔记总结

目录 一、案例总结 1、基础知识 &#xff08;1&#xff09;第1章 通向智能安全的旅程 &#xff08;2&#xff09;第2章 打造机器学习工具箱 &#xff08;3&#xff09;第3章 机器学习概述 &#xff08;4&#xff09;第4章 Web安全基础 2、安全案例 &#xff08;1&#…

github 近期热门项目-2025.7.20

github 近期热门项目-2025.7.20 GitHub 上近期热门或趋势项目的信息可以从多个来源获取,包括 GitHub Trending 页面、技术社区推荐、以及各大技术媒体的报道。以下是一些近期在 GitHub 上备受关注的项目类别和示例: 1. AI 与机器学习项目 随着 AI 技术的快速发展,许多开源…

使用Python清理Excel中的空行和单元格内部空行:初学者指南

前言 作为数据处理人员或办公室工作者,你可能经常遇到Excel文件中存在多余空行或单元格内有多余空行的问题。这些不必要的空白会影响数据的美观性,更重要的是会给后续的数据分析、合并或处理带来麻烦。本文将介绍一个简单的Python脚本,帮助你高效地解决这些问题。 很多工具…

华为欧拉系统(openEuler)安装 Docker 容器完整教程

&#x1f525; 前言&#xff1a;在国产化操作系统日益普及的当下&#xff0c;华为欧拉系统&#xff08;openEuler&#xff09;凭借其稳定性和安全性受到不少用户青睐。但 Docker 官方暂未提供对 openEuler 的原生支持&#xff0c;不过好在 openEuler 与 CentOS 底层架构兼容&am…

数据结构--JDK17新增语法和顺序表

一.yield关键字用于switch语句上的case代码块的返回值举例&#xff1a;二.var关键字作用&#xff1a;当类型名字较长时可以简化代码。注意事项&#xff1a;1.不能使用var来声明字段2.不能使用var来声明方法参数3.不能使用var来声明方法返回类型4.使用时必须初始化&#xff0c;但…

1 渗透基础

目录 基础前沿 1 vulhub环境搭建 1 proxychains工具&#xff1a;编辑配置文件 2 docker docker环境搭建 配置docker的代理&#xff1a; 2 nginx编译安装--FPM 1 php.ini 2 php-fpm 3 nginx 4 nginx php-fpm php 1 基本角色分工 2. 请求处理全流程 步骤 1&#xff…

基于Java+SpringBoot 的榆林特色旅游网站

源码编号&#xff1a;S678源码名称&#xff1a;基于SpringBoot 的榆林特色旅游网站用户类型&#xff1a;双角色&#xff0c;用户、管理员数据库表数量&#xff1a;22 张表主要技术&#xff1a;Java、Vue、ElementUl 、SpringBoot、Maven运行环境&#xff1a;Windows/Mac、JDK1…

Python设计模式深度解析:单例模式(Singleton Pattern)完全指南

Python设计模式深度解析&#xff1a;单例模式&#xff08;Singleton Pattern&#xff09;完全指南前言什么是单例模式&#xff1f;单例模式的三个关键要素基础实现&#xff1a;异常控制式单例Python中的经典单例实现1. 使用 __new__ 方法实现2. 线程安全的单例实现3. 装饰器实现…

LVS 原理详解及部署(包含实验案例)

一、集群和分布式简介1.系统性能扩展方式Scale Up&#xff08;向上扩展&#xff09;&#xff1a;通过增强单台服务器的硬件性能&#xff08;如提升 CPU、内存、存储等&#xff09;来提高处理能力&#xff0c;适用于业务初期或对单点性能要求高的场景。这种方式简单易行&#xf…

两个路由器通过不同的网段互联

一&#xff0c;实验拓扑图&#xff1a;二、实验说明 &#xff1a;在两个接口配置好两个不同网段的的ip地址后是不能相互通信的。经过测试用ospf把两个网段宣告进area 0 是行不通的。最后我们通过静态路由来配置&#xff0c;遇到一个最大的问题是&#xff0c;我们的下一跳地址应…

Python趣味算法:冒泡排序——从理论到极致优化

排序算法是程序员的必修课,而冒泡排序是理解算法思维的绝佳起点。本文将深入解析冒泡排序的7种优化技巧,通过可视化演示+多维度性能分析,带你彻底掌握这一经典算法! 看在每天坚持分享有趣知识的份上,点个关注吧(づ ̄ 3 ̄)づ 关注是我更新的动力 ̄︶ ̄∗ ̄︶ ̄∗) 作者会…

[simdjson] document_stream | iterate_many() | batch_size | 线程加速 | 轻量handle

第七章&#xff1a;文档流 欢迎回来 在前面的章节中&#xff0c;我们学习了如何使用解析器结合填充字符串获取表示JSON根节点的文档&#xff0c;并通过按需API&#xff08;On-Demand API&#xff09;遍历值、对象和数组&#xff0c;同时使用simdjson_result进行错误处理。 到…

【机器学习】向量数据库选型指南:企业内网部署场景

向量数据库选型指南&#xff1a;企业内网部署场景一、选型背景与关键需求 在企业级机器学习应用中&#xff0c;特别是涉及图片、视频等非结构化数据的场景&#xff0c;向量数据库已成为核心基础设施。传统数据库难以高效处理高维向量的相似度检索需求&#xff08;如图片相似性搜…

Django母婴商城项目实践(八)- 数据渲染与显示之首页

8、数据渲染与显示 1 概述 Django作为Web框架,需要一种很便利的方法动态地生成HTML网页,因此有了模板这个概念。模板包含所需HTML的部分代码以及一些特殊语法,特殊语法用于描述如何将视图传递的数据动态插入HTML网页中。 Django可以配置一个或多个模板引擎(甚至是0个,如前…

Redis常见线上问题

文章目录 Redis常见线上问题 引言 报告背景与目的 Redis版本与环境说明 性能瓶颈问题 慢查询分析与优化 高CPU与网络延迟 内存管理问题 内存碎片成因与优化 BigKey与内存溢出 数据一致性与高可用问题 主从同步延迟 脑裂问题与解决方案 持久化机制问题 RDB与AOF对比 核心特性对比…