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

文章目录

  • 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.mzph.cn/diannao/17404.shtml

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

相关文章

stm32启动文件

启动文件由汇编编写&#xff0c;是系统上电复位后第一个执行的程序。主要做了以下工作&#xff1a; 初始化堆栈指针SP_initial_sp 初始化PC指针Reset_Handler 初始化中断向量表 配置系统时钟 调用C库函数_main初始化用户堆栈&#xff0c;从而最终调用main函数去到C的世界 …

linux下使用cmake-gui编译WXQT

一.编译环境 操作系统&#xff1a;Ubuntu 22.04.3 LTS wxWidgets源码&#xff1a;wxWidgets-3.1.5 编译工具&#xff1a;CMake-gui qt版本&#xff1a;5.13.2 二.编译步骤 1.将源码解压。 2.打开CMake-gui&#xff0c;并设置好源码目录和构建目录 3.点击configure 会弹出…

C++模板使用

文章目录 目录 文章目录 前言 一、交换函数(泛型编程) 二、函数模板 2.1 函数模板概念 2.2函数模板格式 2.3使用方法 2.4 函数模板的原理 2.4.1库中的swap 2.5 函数模板的实例化 2.6 模板参数的匹配原则 三、类模板 3.1 类模板的定义格式 3.2类模板声明和定义分离 前言 C语言阶…

数据仓库——分层原理

目录 一、什么是数据仓库 二、数仓建模的意义&#xff0c;为什么要对数据仓库分层&#xff1f; 三、ETL 四、技术架构 五、数仓分层架构 数仓逻辑分层 1、数据引入层&#xff08;ODS&#xff0c;Operational Data Store&#xff0c;又称数据基础层&#xff09;&#xff…

解决 WooCommerce 的分析报表失效问题

今天明月的一个境外电商客户反应网站的 WooCommerce 分析报表已经十多天没有更新了&#xff0c;明明每天都有订单交易可分析报表里的数据依旧是十多天前的&#xff0c;好像更新完全停滞了似的。明月也及时的查看了后台的所有设置&#xff0c;确认没有任何问题&#xff0c;WooCo…

Android刮刮卡自定义控件

效果图 刮刮卡自定义控件 import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import …

类和对象03

六、继承 我们发现&#xff0c;定义这些类时&#xff0c;下级别的成员除了拥有上一级的共性&#xff0c;还有自己的特性。 这个时候我们就可以考虑利用继承的技术&#xff0c;减少重复代码 6.1 继承的基础语法 例如我们看到很多网站中, 都有公共的头部&#xff0c;公共的底…

乡村振兴的乡村人才引进与培养:引进和培养乡村人才,激发乡村发展活力,为乡村振兴提供人才保障

目录 一、引言 二、乡村人才引进与培养的重要性 &#xff08;一&#xff09;人才是乡村振兴的核心动力 &#xff08;二&#xff09;人才是乡村文化传承的载体 &#xff08;三&#xff09;人才是乡村社会治理的基石 三、乡村人才引进与培养的现状 &#xff08;一&#xf…

备战秋招c++ 【持续更新】

T1 牛牛的快递 原题链接&#xff1a;牛牛的快递_牛客题霸_牛客网 (nowcoder.com) 题目类型&#xff1a;模拟 审题&确定思路&#xff1a; 1、超过1kg和不足1kg有两种不同收费方案 ---- 起步价问题 2、超出部分不足1kg的按1kg计算 ----- 向上取整 3、向上取整的实现思路…

移动端应用订阅SDK接入攻略

本文档介绍了联想应用联运移动端订阅SDK接入操作指南&#xff0c;您可在了解文档内容后&#xff0c;自行接入应用联运移动端订阅SDK。 接入前准备 1请先与联想商务达成合作意向。 2.联系联想运营&#xff0c;提供应用和公司信息&#xff0c;并获取商户id、app id、key&#…

谷歌开发者账号身份验证不通过?该怎么办?

我们都清楚&#xff0c;随着谷歌上架行业的快速发展&#xff0c;谷歌政策也在不断更新变化&#xff0c;对开发者账号的审核标准也在不断提升。其中一项要求就是&#xff0c;开发者账号需要进行身份验证才能发布应用。 Your identity couldnt be verified&#xff01;“我们无法…

词法与语法分析器介绍

概述 词法和语法可以使用正则表达式和BNF范式表达&#xff0c;而最终描述文法含义的事状态转换图 Lex与YACC 词法分析器Lex 词法分析词Lex&#xff0c;是一种生成词法分析的工具&#xff0c;描述器是识别文本中词汇模式的程序&#xff0c;这些词汇模式是在特殊的句子结构中…

二叉树的实现(递归实现)

前言&#xff1a;本文讲解通过递归的方式实现二叉树的一些基本接口。 目录 通过左右子树的方式实现二叉树&#xff1a; 二叉树的遍历&#xff1a; 求二叉树结点的个数&#xff1a; 二叉树所有节点的个数&#xff1a; 二叉树叶子节点的个数&#xff1a; 求第k层节点的节点…

4,八种GPIO模式

资料来源:【STM32基础学习】八种GPIO模式总结-云社区-华为云 (huaweicloud.com) 【STM32基础学习】八种GPIO模式总结-云社区-华为云 (huaweicloud.com) 【STM32基础学习】八种GPIO模式总结-云社区-华为云 (huaweicloud.com) 仅作个人自学笔记&#xff0c;如有冒犯&#xf…

电子阅览室解决方案

一.方案概述 “电子阅览室”概念一经提出&#xff0c;就得到了广泛的关注&#xff0c;纷纷组织力量进行探讨、研究和开发&#xff0c;进行各种模型的试验。随着数字地球概念、技术、应用领域的发展&#xff0c;电子阅览室已成为数字地球家庭的成员&#xff0c;为信息高速公路提…

uniCloud云存储uni-cdn七牛云扩展存储-开发uniapp项目节约开发成本

为什么要使用uniCloud的扩展存储&#xff0c;那就是省钱&#xff0c;而且DCloud也一直在推uni-cdn&#xff0c;我在项目中也使用七牛云的扩展存储&#xff0c;确实是省钱&#xff0c;如果你的项目使用到大量的图片后者音视频&#xff0c;这些的算计可以帮你省不少钱。下面就通过…

【状态机动态规划】3129. 找出所有稳定的二进制数组 I

本文涉及知识点 动态规划汇总 LeetCode 3129. 找出所有稳定的二进制数组 I 给你 3 个正整数 zero &#xff0c;one 和 limit 。 一个 二进制数组 arr 如果满足以下条件&#xff0c;那么我们称它是 稳定的 &#xff1a; 0 在 arr 中出现次数 恰好 为 zero 。 1 在 arr 中出现…

dp背包问题

英雄联盟游戏中新出n个英雄&#xff0c;用长度为n的教组 costs 表示每个英雄的定价&#xff0c;其中 costs[i]表示第i个英雄的点券价格。假如你一共有coins点券可以用于消费&#xff0c;且想要买尽可能多的英雄并日选择英雄按costs[i]给出顺序获取。给你价格数组 costs 和金币量…

Golang | Leetcode Golang题解之第116题填充每个节点的下一个右侧节点指针

题目&#xff1a; 题解&#xff1a; func connect(root *Node) *Node {if root nil {return root}// 每次循环从该层的最左侧节点开始for leftmost : root; leftmost.Left ! nil; leftmost leftmost.Left {// 通过 Next 遍历这一层节点&#xff0c;为下一层的节点更新 Next …

vue3 uni-app 中小程序实现 底部tabbar 中间凸起部分 或者说自定义底部tabbar [保姆级别教程]

1、先来看一下效果 2、代码实现 我们还是在 pages.json 中正常配置我们底部的tabbar 但是需要 添加一个字段 "custom": true, //开启自定义tabBar 不填每次原来的tabbar在重新加载时都回闪现 3、 在 pages同一级 或者 里面创建一个 子组件 用来放我们的模版 4、 …