【Java面试】五、MySQL篇(下)

news2024/9/17 3:22:38

文章目录

  • 1、事务的特性
  • 2、并发事务问题
  • 3、事务的隔离级别
  • 4、undo log 和 redo log
    • 4.1 底层结构
    • 4.2 redo log
    • 4.3 undo log
  • 5、MVCC
    • 5.1 隐式字段
    • 5.2 undo log 版本链
    • 5.3 ReadView
    • 5.4 ReadView的匹配规则实现事务隔离
  • 6、MySQL的主从同步原理
  • 7、分库分表
    • 7.1 垂直分库
    • 7.2 垂直分表
    • 7.3 水平分库
    • 7.4 水平分表
    • 7.5 分库分表之后的问题
  • 8、面试

在这里插入图片描述

1、事务的特性

一组操作,同成功,同失败。开启事务后,所有操作作为一个整体去提交或撤销。

在这里插入图片描述
事务的特性:ACID

  • 原子性A:事务是最小的操作单元,不可分割
  • 一致性C:事务完成后,所有的数据保持一致的状态
  • 隔离性I:数据库的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行
  • 持久性D:落盘,事务一旦提交,改变就是永久的

具体以银行转账的例子描述ACID:A向B转500块,这个操作不可再分割,转账过程,A账户扣除了500,B账户必须增加500,数据要一致。A向B转账的过程中,不能受其他事务和操作的干扰,即隔离性。最后事务提交,数据落盘,即持久化

2、并发事务问题

  • 脏读
  • 不可重复读
  • 幻读

在这里插入图片描述

脏读即:事务B更新了数据,但还没commit,A事务就给读走了

在这里插入图片描述

解决:将隔离级别由读未提交 -> 改为 -> 读已提交

隔离级别改为读已提交后,发现会出现两次读取的结果不一致的情况 ⇒ 不可重复读即:A刚开始读的id=1的数据,值为x,期间事务B又更新并commit了id=1的这条数据,此时A事务第二次读,发现两次数据不一样

在这里插入图片描述

解决:将隔离级别由读已提交 -> 改为 -> 可重复读

改为可重复读的隔离级别后,又出现了幻读 ⇒ 幻读即:事务A先查id=1数据,发现没有。然后准备insert id=1的数据,但期间事务B写入了id=1的数据,事务Ainsert时失败,于是事务A再查id=1数据,发现还是没有(可重复读的隔离级别),事务A自己感觉见鬼了

在这里插入图片描述

3、事务的隔离级别

并发事务有脏读、不可重复读、幻读三个问题。以下四种隔离级别,对应的问题如下:(√即存在这个问题,x即不存在这个问题)

在这里插入图片描述

总之:

  • 读未提交 ⇒ 存在脏读问题
  • 读已提交 ⇒ 存在不可重复读问题(Oracle默认的隔离级别)
  • 可重复读 ⇒ 存在幻读问题(MySQL默认的隔离级别)
  • 串行化 ⇒ 无并发事务的三大问题,但性能不高

4、undo log 和 redo log

4.1 底层结构

缓冲池:

  • buffer pool,主内存的一个区域,里面存了磁盘上经常操作的那些数据
  • 增删改查时,先去缓冲池找,没找到再去磁盘加载
  • 以一定频率把池里的数据刷回磁盘,减少IO次数,提高速度

数据页:

  • InnoDB存储引擎管理磁盘的最小单元
  • 每页大小默认16KB
  • 每页中存的是行数据

在这里插入图片描述

该架构下,存在问题:如果从缓冲池刷数据到磁盘时,磁盘所在服务器宕机或IO异常,缓冲池的数据在内存,断电会丢失 ⇒ redo log

4.2 redo log

  • 重做日志,包括redo log buffer(存缓冲池中)、redo log file(存磁盘中)
  • 用来保证事务的持久性的

增删改的事务提交后,写到缓冲池、缓冲池的redo log、磁盘的redo log,此时缓冲池数据刷回磁盘失败时,可用磁盘的redo log去做恢复。问:你有空往磁盘的redo log写数据,没空直接把增删改的数据写回磁盘吗?⇒ 前者是追加,顺序写,后者是磁盘寻道,随机写,性能差别很大。
在这里插入图片描述
最后,如果缓冲池的数据成功刷回磁盘了,那磁盘里的redo log就没用了,会自动定期清理。

rodo log,简言之,用于保证持久化的,当缓冲池数据刷回磁盘失败时,靠redo log恢复。

4.3 undo log

作用:

  • 用于做回滚
  • 用于MVCC(多版本并发控制)

undo log是逻辑日志,客户端做delete,undo log中记录insert。客户端update,undo log也update,但update成前一版数据。总之就是逆操作。rollback时,执行undo log即可。undo log保证的是事务的一致性和原子性。

5、MVCC

Multi-Version Concurrency Control,多版本并发控制。即维护了一条数据的多个版本,使得并发事务下读写操作没有冲突(读哪个版本,是隔离级别决定的,但多个版本的维护,是MVCC支持的),或者说是保证事务隔离性的。

在这里插入图片描述
MVCC的实现,依赖三个东西:

  • 隐式字段
  • undo log日志
  • readView

5.1 隐式字段

每张表会有三个额外字段:

在这里插入图片描述

一个字段记录最近操作这条数据的事务ID,一个字段记录上一个版本的数据的内存地址:

在这里插入图片描述

5.2 undo log 版本链

insert、update、delete时,产生undo log,用于回滚和版本控制。刚开始的状态:

在这里插入图片描述

事务2修改id = 30数据的age为3,得到版本1的数据,表里的指针指向undo log最开始的初始数据:

在这里插入图片描述

事务3将id = 30数据的name改为A3:此时,表里存第二个版本在undo log的内存地址,这个地址指向undo log里存版本1的数据

在这里插入图片描述

事务4将id = 30数据的age改为10:

在这里插入图片描述

不同事务或者相同事务对同一条记录进行修改,针对该记录,在undo log中生成一条数据记录,并由db_roll_prt字段形成版本链表。链表的头部是最近那个版本的数据,链表尾部是最早的原始数据。

5.3 ReadView

  • 当前读:读取的是记录的最新版本
  • 快照读:读已提交的隔离级别下,每次select,生成一个快照去读。可重复读的隔离级别下,开启事务后的第一个select执行,会记录一个快照,后面每次select都是在这个快照读

ReadView是快照读时,MVCC提取哪个版本数据的依据,记录并维护当前未提交的事务ID。包含字段:

在这里插入图片描述

以下图为例,事务5在第一次读数据的时候:活跃事务Id(即未提交的事务)有三个(3、4、5),因此m_ids数量为3,最小事务ID为3,预分配事务ID为6(5+1),creator_trx_id为5

在这里插入图片描述
不同的隔离级别,生成 ReadView 的时机不同:

  • READ COMMITTED:在事务中每一次执行快照读时生成 ReadView
  • REPEATABLE READ:仅在事务中第一次执行快照读时生成 ReadView,后续复用该 ReadView

5.4 ReadView的匹配规则实现事务隔离

前面undo log中生成了一个版本链,而一个事务可以访问哪个版本的数据,由每个版本数据的trx_id和ReadView里的值决定。规则如下(trx_id表示这个版本的数据的db_trx_id):

在这里插入图片描述

以上规则很好理解,比如trx_id < min_trx_id,说明产生这个版本数据的事务ID,比当前未提交的所有事务里面最小的事务ID还要小(事务ID小,说明这个事务开启的早,持续时间更久),即这个版本的数据已经提交了,那当前事务自然是可以访问的。相反trx_id > max_trx_id,说明产生这个版本的事务Id,比所有未提交的事务里最年轻的事务,还要年轻,因此,当前事务不可访问这个版本的数据

读已提交的隔离级别下:

分析事务5的两次查询,其readview如下,每次select都会产生一个select:
在这里插入图片描述

以第一个readview为例:并发事务产生了四个版本的数据,最近的一条数据trx_id为4,带入右边规则:

4 == 5,不成立
4 < 3,不成立
4 > 6,不成立
3 <= 4 <= 6成立,但4345中的一个,整体不成立

都不成立,因此,事务5当前不可以访问这个版本的数据。再看上一个版本的数据,trx_id为3

3 == 5,不成立
3 < 3,不成立
3 > 6,不成立
3 <= 3 <= 6成立,但3345中的一个,整体不成立

都不成立,因此,这个版本的数据,事务5当前还是不能访问。再看上一个版本的数据,trx_id为2

2 == 5,不成立
2 < 3,成立

成立,可以访问。根据读已提交的隔离策略,可以看到。读到的正是事务2提交的那一版,符合"读已提交"的策略。
在这里插入图片描述

同理,事务5在第二次select时,读已提交策略下会生成了新的ReadView,ReadWiew各个字段如图中所标:

在这里插入图片描述
最近的一条数据trx_id为4,带入右边规则:

4 == 5,不成立
4 < 4,不成立
4 > 6,不成立
4 <= 4 <= 6成立,但4345中的一个,整体不成立

都不成立,因此,事务5当前不可以访问这个版本的数据。再看上一个版本的数据,trx_id为3

3 == 5,不成立
3 < 4,成立

因此,当前(第二次select时)事务5可以看到DB_TRX_ID为3的数据,正好是事务3提交的那一版本,符合"读已提交"的策略。最后,看下可重复读事务隔离策略下情况:
在这里插入图片描述

带入4条规则,可以得出,事务5两次select,可以拿到的版本都是事务2提交的那个版本。

由此,可以看到MVCC保证了MySQL事务隔离性。 当然,事务的隔离性还有锁在处理,比如一个事务获取了一行数据的排他锁,那其他事务就不能再获取该行的其他锁,其他事务如果尝试获取这行数据的共享锁或排他锁,都会被阻塞,直到持有排他锁的事务释放锁或事务结束。

6、MySQL的主从同步原理

一个Java服务,配置连接了主库和从库,其中,主库用于写,从库用于读

在这里插入图片描述
主从之间实现数据同步的核心 ⇒ 二进制日志binlog(记录了DDL,如create,以及DML,如insert)

在这里插入图片描述

insert一条数据,实现步骤:

  • insert后,主库将变更写进Binlog
  • 从库有线程IoThread去读主库的Binlog,并将变化写入到从库自己的中继日志Relay Log
  • 从库重做中继日志的时间,使用线程SQLThread进行insert
  • 同步完成

7、分库分表

主从结构下,分担了读数据的压力,但解决不了海量数据的存储问题。 ⇒ 分库分表

需要分库分表的时机:项目的业务数据越来越多或做的产品突然火了,单表数据量达1000万行或者20G以后。此时,正常的SQL优化或者加索引解决不了性能问题。
在这里插入图片描述

拆分策略:

  • 垂直分库
  • 垂直分表
  • 水平分库
  • 水平分表

在这里插入图片描述

7.1 垂直分库

以表为依据,按业务的不同,将不同业务的表分配到不同的库中。不同的微服务,连接自己的库,如下:

在这里插入图片描述

改成多个库,如此,在高并发下,提高了磁盘的IO以及数据库连接数

7.2 垂直分表

以字段为依据,根据字段属性将不同字段拆分到不同表中。拆分规则:

  • 把不常用的字段单独放一个表
  • 把text、blob等大数据类型的字段分出来放到一个附表

如下,商品订单表,id、name、category、brand、title字段,属于常用的字段,List或者点开购物应用就要展示的数据。而description属于点开某个商品看详情的时候才能用到的字段,且属于大字段,可做如下拆分:将description单独分一个表,注意id做关联(注意,下面垂直分表后,图中画的是分后的两个表在两个库,这个没限制,也可能在同一个库):
在这里插入图片描述

如此,冷热数据分离,减少了不必要的IO(在tb_sku表select * 也不会把大字段description从磁盘读出来),两表互不影响。

7.3 水平分库

将一个库的数据拆分到多个库中,表结构一样,存的数据不一样。
在这里插入图片描述
正常一个Java微服务连接一个库,查数据时,想成功路由到数据所在的库,可以考虑:

  • 根据id节点取模
  • 按id也就是范围路由,节点1(1-100万),节点2(100万-200万)

7.4 水平分表

将一个表的数据拆分到多个表中(这几个表也可以放在同一个库)

在这里插入图片描述
数据的查询则和水平分库一样,可以考虑取模。如此,可以解决单一表数据量过大而产生的性能问题。

7.5 分库分表之后的问题

  • 分布式事务一致性问题(一个业务操作,需要更新多个数据库,控制事务,同成功同失败)
  • 跨节点关联查询
  • 跨节点分页、排序函数
  • 主键避重

⇒ 分库分表后,引入分库分表中间件解决以上问题以及路由问题:

  • sharding-sphere
  • mycat

在这里插入图片描述
最后:

  • 水平分库,将一个库的数据拆分到多个库中,解决海量数据存储和高并发的问题
  • 水平分表,解决单表存储和性能的问题
  • 垂直分库,根据业务进行拆分,高并发下提高磁盘IO和网络连接数
  • 垂直分表,冷热数据分离,多表互不影响

8、面试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

[NISACTF 2022]easyssrf、[NISACTF 2022]level-up

[NISACTF 2022]easyssrf 使用dirsearch扫描后没发现什么路径 尝试访问127.0.0.1&#xff0c;成功了 访问127.0.0.1/flag.php提示有文件/fl4g 使用file://协议读取文件/fl4g&#xff0c;提示除此页面外还有一个ha1x1ux1u.php页面。 file:///fl4g 直接访问&#xff0c;发现GET…

C++240527

定义自己的命名空间 my_sapce&#xff0c;在 my_sapce 中定义 string 类型的变量 s1&#xff0c;再 定义一个函数 完成 对字符串的逆置 。 #include <iostream>//导入 标准命名空间&#xff0c;cout 和 endl 标识符 存在于标准命名空间中 using namespace std;//定义了自…

C++ 函数模板与模板函数

一 代码重用技术 函数 类与对象 继承与派生 多态&#xff08;函数重载、运算符重载、虚函数、纯虚函数与抽象类&#xff09; 泛型程序设计 通用的代码需要补受数据类型的影响&#xff0c;并且可以自动适应数据类型的变化&#xff0c;这种程序设计类型称为泛型程序设计。 二 模…

特殊矩阵的压缩矩阵

目录 前提条件&#xff1a; 类型&#xff1a;对称矩阵&#xff0c;三角矩阵、三对角矩阵、稀疏矩阵 1&#xff1a;对称矩阵&#xff1a; 定义&#xff1a;n阶矩阵A 中任意一元素都有ai,jaj,i(1<i,j<n) 图像&#xff1a; 表达式&#xff1a; 计算过程&#xff1a; …

类 和 对象(二)

构造方法 接上篇&#xff0c;若每次都想下面的setDate方法给对象初始化&#xff0c;未免比较麻烦&#xff0c;那有什么方法可以让初始化更加简便呢&#xff1f; public void setDate(int year, int month, int day){this.year year;this.month month;this.day day;}答&#…

服务器端口号,如何避免与公共端口冲突

首先&#xff0c;我们需要明确什么是服务器端口号。服务器端口号是计算机操作系统分配给网络应用程序的一个数字标识&#xff0c;用于区分不同的网络服务。每个网络服务都需要一个唯一的端口号来进行标识&#xff0c;以便在通信过程中能够准确找到对应的服务。 为了避免与公共端…

恒创科技:Linux 服务器和 Windows 服务器哪个更好?

选择正确的服务器系统至关重要&#xff0c;目前广泛使用的选项是 Windows 服务器 和 Linux 服务器&#xff0c;它们各有优缺点。本文将比较 Linux 与 Windows 服务器&#xff0c;让我们来看看它们的主要区别&#xff0c;然后再决定哪种操作系统适合使用。 主要区别&#xff1a;…

Windows下mingw32编译ffmpeg5.1.4实现rtsp拉流

由于客户要求&#xff0c;要在Windows下使用mingw32编译&#xff0c;去ffmpeg.org下载需要编译的版本&#xff0c;使用msys2方法进行编译&#xff0c;使用QT5.10的编译器&#xff0c;基本上把网上的方法试了个遍&#xff0c;编译全部库总是报错出问题 查看了ffbuild文件夹中con…

Mac 电脑给android手机传输文件提示 No android device found

在开发过程中&#xff0c;我们有时候会有在电脑和手机之间传输文件的需求。 Mac电脑给android手机传输文件并不是很方便。 Google 官方提供了一个软件叫Android File Transfer&#xff0c;这个软件免费且好用。 Android File Transfer下载地址 但是使用过程中会遇到一些问题…

Android:使用Kotlin搭建MVI架构模式

一、简介MVI架构模式 M&#xff1a;Model 数据层&#xff0c;包含应用数据和业务逻辑V&#xff1a;View 界面层&#xff0c;在屏幕上显示应用数据&#xff0c;包含与界面相关的状态和界面逻辑&#xff0c;根据界面状态对象更新UI&#xff0c;界面状态定义是不可变的。这样的主要…

完全背包+背包装满 总结

目录 1.背包恰好装满 &#xff08;1&#xff09;问题是什么 &#xff08;2&#xff09;问题的有效状态和无效状态 &#xff08;3&#xff09;问题的常考形式&#xff0c;以及如何去处理 1.值的大小 2.组合个数 3.排列个数 2.例题 A. Cut Ribbon HDU1114 Piggy-Bank …

OpenHarmony实战开发——网络组件axios可以在OpenHarmony上使用了

什么是axios 上古浏览器页面在向服务器请求数据时&#xff0c;因为返回的是整个页面的数据&#xff0c;页面都会强制刷新一下&#xff0c;这对于用户来讲并不是很友好。并且我们只是需要修改页面的部分数据&#xff0c;但是从服务器端发送的却是整个页面的数据&#xff0c;十分…

C++: 二叉搜索树及实现

目录 一、二叉搜索树的概念 二、二叉搜索树的操作 2.1插入 2.2删除 1.有左子树&#xff0c;无右子树 2.有右子树&#xff0c;无左子树 3.有左子树和右子树 三、二叉搜索树的实现 要点 前言&#xff1a;为了学习map和set&#xff0c;需要先学二叉搜索树作为铺垫。 一、…

计算机毕业设计 | SpringBoot招投标系统 任务发布网站(附源码)

1&#xff0c;绪论 在市场范围内&#xff0c;任务发布网站很受欢迎&#xff0c;有很多开发者以及其他领域的牛人&#xff0c;更倾向于选择工作时间、工作场景更自由的零工市场寻求零散单子来补贴家用。 如今市场上&#xff0c;任务发布网站鱼龙混杂&#xff0c;用户需要找一个…

AIGC 008-IP-Adapter文本兼容图像提示适配器用于文本到图像扩散模型

AIGC 008-IP-Adapter文本兼容图像提示适配器用于文本到图像扩散模型&#xff01; 文章目录 0 论文工作1 论文方法2 效果 0 论文工作 这篇论文介绍了 IP-Adapter&#xff0c;一种 高效地将预训练的图像到图像转换模型适应到新领域 的方法。它通过在预训练模型的 输入端 添加一个…

Python考试复习--day2

1.出租车计费 mile,waitmap(int,input().split(,)) if mile<3:money13wait*1 elif mile>3 and mile<15:money13(mile-3)*2.3wait*1 else:money1312*2.3(mile-15)*2.3*(10.5)wait*1 print({:.0f}.format(money)) 【知识点1】&#xff1a; map() 函数 【知识点1】&…

数字水印 | 离散余弦变换 DCT 基本原理及 Python 代码实现

目录 1 基本原理2 代码实现3 图像压缩 1 基本原理 参考博客&#xff1a;https://www.cnblogs.com/zxporz/p/16072580.html D C T \mathsf{DCT} DCT 全称为 D i s c r e t e C o s i n e T r a n s f o r m \mathsf{Discrete\ Cosine\ Transform} Discrete Cosine Transfo…

HTTPS证书——网站如何实现HTTPS访问?

实现网站HTTPS访问可以简化为以下四个基本步骤&#xff0c;确保过程既通俗易懂又条理清晰&#xff1a; 1. 申请SSL证书 - 目的&#xff1a;SSL证书是实现HTTPS加密的关键&#xff0c;它验证了网站的身份&#xff0c;并提供了加密数据所需的密钥。 - 操作&#xff1a;首先&…

面试手撕——使用两个线程交替打印1-100

记录一下使用两个线程交替打印1-100的操作: /*** description: 使用两个线程交替打印1-100* author: Jay* create: 2024-05-27 21:29**/ public class print_1_to_100 {static volatile int flag 1; //此处需要加关键字volatile保证变量之间的可见性&#xff0c;否则程序将会…

TS(TypeScript)中Array数组无法调出使用includes方法,显示红色警告

解决方法 打开tsconfig.json文件&#xff0c;添加"lib": ["es7", "dom"]即可。 如下图所示。