• MySQL(7)


    MySQL(7)

    前言:

    本文 主要 介绍 面试 常考 索引 事务 中的 事务。

    老规矩:

    在进入文章前,我们来回忆一下上文的内容。

    联合查询 (多表查询):

    1.自连接 : 通过 对本身笛卡尔积操作, 将不好查找的 行与行之间 转化 相对 好查找的 为列 和 列

    (属于 SQL 中 的 奇淫巧计, 用来处理 一些特殊的场景的问题)

    2.子查询 : 子查询是指嵌入在其他sql语句中的select语句,也叫嵌套查询

    (也就是 将 多个 select 合并成 一个 , 简单 来说 就是 套娃, 他能 一直套娃下去。)

    下面就是 我们 面试 常考的 索引 。

    索引:

    这里我们 如何 理解 索引?

    1.索引 存在 的意义 , 提高了查找的效率

    2.索引 存在 付出的 代价: (相对 索引带来 的 坏处)

    a) 空间代价

    b)时间代价 针对 增删 改

    索引 带来 的好处 :提高了 查找的 速度。

    索引 带来的 坏处 : 1. 占用 了 更多 的 空间, 2. 拖慢了增 删 改 的 速度。

    3.虽然如此,索引仍然会广泛使用,实际要求中,经常是 “一写 多读”

    4.索引背后的 数据结构 : B+树

    a)其他的结构 行不行?

    二叉搜索 (AVL树 , 红黑树)

    答: 不太行, 树的 高度 太高,导致 IO 访问次数太多。

    哈希表 呢?

    也不太行 哈希表不支持范围查找

    b) 这里我们 先 认识 了B 树

    N叉搜索树 , 每个节点上包含了 N个记录。N个记录 就分成了N + 1 个 区间,对应 N + 1 个子树 ,就可以 通过这样的方式 快速 确定当前要查找的值 在那个区间,进一步 进行 快速筛选。

    c) B+树 又在B树的基础上做出了 改进

    首先, 每个节点 上 都包含 N个 key, N个key 分成了 N个区间

    其次 ,每个 节点上的值 ,都会在子节点上体现, =》 叶子 节点 上就包含了 所有数据的全集。

    再次 , 叶子 节点 在通过 链表的 形式 进行 首位相连。

    此时 带来 最大的好处, 一方面,可以更高效的进行范围查找,另一方面,因为叶子节点是数据的全集,非叶子节点就只保存 key即可,占用空间少,可以在内存中缓存, 有进一步的减少了 IO 次数。

    下面就 进入本文内容。

    事务

    事务: 事务诞生的目的就是为了把若干个独立的操作给打包成一个整体。


    这里 就可以 举 一个 形象的例子:


    我们 都有 女神 吧(别骗自己说没有), 那么与女神 约会 是不是 需要 钱,这时候我们是不是 需要去取钱 , 但到了 约会那天女生没来(鸽了你),冤大头的我们来了 ,这里取这 钱是不是就没有意义了 还不如 存在 银行 吃利息。

    这里我 我们的 事务 就算 将 这两件事 打包到一起 。

    解释: 这件事 要么 就 一次性完成 (将 取钱,与 女神约会都执行了)

    要么就是 一个 操作 都不执行(女神不来,我们还当啥冤大头,直接不取 钱,也不去了)。

    不需要 存在 只执行了 第一步 不执行了 第二步的 中间状态。

    这里我们 回到我们的 MySQL :

    在 SQL 中 ,有 的 复杂 的任务 需要多个SQL 来执行。

    有点 时候,也同样 需要打包在一起, 前一个SQL 是为了给后一个SQL 提供 支持,如果 后 一个SQL 不执行了或者执行出现问题了 ,前一个SQL 也就失去意义了。

    这样的情况,我们就能借助 事务 来进行。

    总之,事务就是把很多东西打包在一起,要做就全做完,不做就一个也别做。

    在MySQL 中 这样的特点 (要么 全部执行完,要么一个都不执行,任务不可以被细分)我们就成为 事务的原子性

    事务的原子性

    原子性: 要么 全都执行完,要么一个都不执行,任务不可以在被细分了。

    这里举个例子:

    举个例子:

    A想要从自己的帐户中转1000块钱到B的帐户里。那个从A开始转帐,到转帐结束的这一个过程,称之为一个事务。在这个事务里,要做如下操作:

      1. 从A的帐户中减去1000块钱。如果A的帐户原来有3000块钱,现在就变成2000块钱了。
      1. 在B的帐户里加1000块钱。如果B的帐户如果原来有2000块钱,现在则变成3000块钱了。

    如果在A的帐户已经减去了1000块钱的时候,忽然发生了意外,比如停电什么的,导致转帐事务意外终止了,而此时B的帐户里还没有增加

    1000块钱。那么,我们称这个操作失败了,要进行回滚。回滚就是回到事务开始之前的状态,也就是回到A的帐户还没减1000块的状态,

    B的帐户的原来的状态。此时A的帐户仍然有3000块,B的帐户仍然有2000块。

    我们把这种要么一起成功(A帐户成功减少1000,同时B帐户成功增加1000),要么一起失败(A帐户回到原来状态,B帐户也回到原来状态)的操作叫原子性操作。

    如果把一个事务可看作是一个程序,它要么完整的被执行,要么完全不执行。这种特性就叫原子性。

    补充: 有没有疑问 事务 的 这个原子性 到底是 咋保证 的呢?

    理论 我们 都 清楚 : 要么 就全都 执行 成功,要么 就 一个都不执行。

    那么 原子性 到底是 如何保证的呢?

    实际上我们在执行第二个SQL之前,我们并不能预知这次执行是否会失败,这里我们 的 做法

    其实 还是 的先执行第一个SQL ,执行完成 之后 在执行 第二个SQL 试试看。

    总结:

    也就是说:实际上 在处理事务的时候,并不像所说 说的那样【要么就全部执行成功,要么就一个都不执行】,

    这里 我们并不能预知突发事件的发生,所以不管能否执行成功,我们都需要去执行一下(该执行还是要执行一下)。

    如果我们 的SQL 执行的失败之后,由数据库自动执行一些"还原" 性 的工作,来消除 前面的 SQL 带来的影响。

    这里举个 例子 :

    现在 显卡是不是 到了 大矿难 , 有很多 显卡 回流 到 了 市场, 一些 厂商 是不是 去 回收 矿卡,翻新 然后 在 卖给 我们 ,这里 对于 我们

    普通用户 来说,是很难 区分 这是 一张 新卡,还是 翻新卡。 翻新后 的 卡 我们 难以 知道 他 锻炼了 多久,这里 就与 我们 数据库 执行 还

    原 工作 一样, 消除了 SQL执行失败带来的影响,将使用 过的 痕迹 抹除了 (其实 他还是 执行 过 SQL 语句)。

    这里 还原的 操作 就叫 做 回滚 (rollback)。

    补充:

    这里 我们 在 来一个问题 : 数据库是如何知道该还原成 原来的 值 的呢?

    这里 数据库 会 有个 小本子 (整个的记录过程搭配了日志 + 数据库内置的一些表来完成),将执行 过的每个操作,都给记录下来。

    既然能 还原 是不是 可以 大胆放心大胆的删除数据库呢?

    这里 虽然能还原 但 不要随便 做 删库 操作,数据库 要 想记录上面的 详细 操作, 也是 要消耗 大量 的时间 和 空间的, 因此这个记录势必 不会保存那么久。

    如: 你的数据库是 进行了 一年的 时间沉淀出来的数据,但是你的这些记录可能 只 记录了 最近 几天的操作。

    (这样 恢复 的 最多是 你 最近几天的 操作)。

    这里 想要 恢复 这些 数据, 还得靠 我们备份的数据。

    事务的使用

    (1) 开启事务:start transaction;

    (2)执行多条SQL语句

    (3)回滚或提交:rollback/commit;

    1、当我们将要执行多句SQL时,先输入 start transaction;

    2、之后,便是执行多行 sql 语句。

    3、最后 执行完之后,我们要以rollback / commit作为返回

    rollback 代表执行失败,进行“回滚”,而 commit 就是执行成功提交的意思

    start transaction;
    // transaction 与 commit 之间,就是事务中的若干操作
    -- 阿里巴巴账户减少2000
    update accout set money=money-2000 where name = '阿里巴巴';
    -- 四十大盗账户增加2000
    update accout set money=money+2000 where name = '四十大盗';
    commit;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    事务相关的面试题

    1.谈谈 事务的 基本 特性

    四个基本的特性:

    1.原子性: 要么 全都执行完,要么一个都不执行,任务不可以在被细分了。


    2.一致性 : 在事务执行之前,和执行之后,数据库中的数据都得是合法的


    列如: 你转账完成 之后,不能够出现账户为负数的情况。


    3.持久性 : 书屋 一旦提交之后,数据就持久化存储起来 (数据写入到 磁盘上)。

    4.隔离性(重点):隔离性描述的是,事务并发执行时候,产生的情况 !!!

    在 解决 解决 隔离性 这个 难点 时 我们 来 了解 一下 什么是 并发 :

    并发 编程是当下 最主要 的 一个 编程的方式(写出来的代码,是并发式执行的)。

    这里 并发式 执行 其实 就 算一心 两用 : 如 上课 : 我们肯定 有过 人在上课 ,心里 想的 下课 吃点啥,或 晚上 玩啥, 和喜欢 的 人 说些啥。

    另外 : 我们 人脑 是 不擅长并发, 但计算机特别擅长

    这里 为啥 电脑擅长 并发 呢 ? 这里 感兴趣 可以 百度, 这里 就 跳过 (算一个 扩充)。

    了解 啥是 并发(一心多用 ) 那么 我们 来 了解 一下 ,数据库的并发执行。

    数据库的 并发执行


    在数据库中,并发执行多个事务的时候,修改 / 读取的 收据,是同一个数据的时候,就可能 会出现一些问题。而事务的隔离性就是解决上述问题。

    所以我们这里事务的隔离性,主要就是针对并发执行事务的场景。

    因此要想理解并发执行事故,我们就必须要理解什么是并发,并发:就是同时执行多个任务。

    那么我们这里的并发执行事故:一个数据库服务器同时执行多个事务。

    并发执行事务可能 带来 问题

    1.脏读 问题


    举例: 有一天 小明同学 去办公室,听到 老师们谈论 说 下星期 一 学校准备 组织 秋游,这时 小明 同学,得知了 这个 消息, 就很高兴的

    跑到班级,去和同学讲,下星期 一 学校组织 秋游, 然后 全班 同学都知道了 这个消息, 但 到达了星期一 ,结果 学校 临时 变卦 换成了

    星期 五 组织 秋游, 此时 这个 星期一组织秋游 这个信息 ,就成为了 一个脏信息, 是 一个 中间信息 ,并不是 最终 的 信息 ,这 就是

    一个 脏读 问题 。


    放在数据库中:事务A在对某个数据进行修改的同时,事务B 去 读取了 这个 数据。此时,事务B 读到的很可能是一个“脏数据”(这个数据是一个临时的结果,而不是最终的结果)

    出现脏读问题的原因:就是事务与事务之间没有进行任何的隔离。其实加上一些约束限制,就可以有效的避免脏读问题。

    下面 我们 就来 谈谈 如何 解决我们的 脏读问题

    2.脏读问题 的 处理方法


    1.给写 操作 加锁

    2.再就修改 的 过程中,别人不能读(加锁的 状态)

    3.等修改完成之后,别人才能读(解除加锁)

    还是 上个 例子 :

    这里 老师 和 同学 们 约定 好 说 :秋游时间还决定 出来,现在只能 知道 再 那个 时间段 (如 :下星期 ),先不会 告诉同学,

    等 学校通知下来我们 才 会 统一 告诉 同学们, 所以 别着急。

    这里 学生们 得 到 的 信息 就 会 是 准确 秋游的时间, 就不再 会是 中间 的数据了。

    一旦加了 这个 写 锁 之后,意味 着 事务之间的隔离性就高了,并发性就降低了。

    (如: A 事务 上了 锁 , B 事务 无法 访问 A 的 事务,这里 A事务性 的隔离性 就 提高了, 那么 同时 进行A 事务 和 B 事务 的 可能性 就 降低了, 这里 并发 性 就 降低了)。

    这里我们的 事务 上了锁 , 我们的事务 就 能 解决 所有 问题吗?

    其实 是 不 的 , 下面 就让我们 来看看 ,事务的 不可重复读问题。

    3.不可重复读问题

    在这里插入图片描述

    4.不可重复度的 处理方法

    这里 解决 不可重复 度 也非常简单 还是 上锁,只不过 不仅 给 写 上锁 ,同时 给 读 也 上锁,

    这里 还是 拿 上面 写博客 来 举例子:

    有位 读 者 刚刚 在 读 博客 时, 不小心刷新 了 一下, 这时 原来 没有修改的博客 变成了 修改后的博客, 那么 此时 读者 一脸 蒙蔽 刚

    刚还有的 内容居然没有了,这时候 他就 很难受,他就找到 作者 说, 你能不能 跟我 约定 一下,你下次 再 修改博客 的时候 能不能 等 我

    读完才 去修改, 这时 作者也不太好意思 ,那么久 答应了 这个 请求。

    这时 是不是 作者写的 时候 上了锁 ,读者 读不了 , 在 发布 博客 后, 有 读者 在读 文章 ,作者 修改不了, 当没有读者时 ,在重新将

    修改的文章更改。这里就给 读 也上了锁。

    在这里插入图片描述


    此时 事务 之间的并发 性 又降低了 , 隔离性 又 提高 了。

    不难得出 : 并发性 和 隔离性 是二者不能得兼的

    这里 要么程序 执行速度块 , 并发性 高 ,这里 隔离性就 低 (容易出错 ), 要么 程序执行 速度慢 但 程序 不容易 出错 (准确性) 隔离性 高 ,并发性 低。

    这里 想要程序 快 或 程序 不容易出错 .

    这件事 就需要 按照 实际情况 来进行 取舍。

    通过上面 就可以 小总结 一下 : 隔离性 与 并发性

    隔离性 : 一个 一个 的 来 (每次执行一个事务)

    并发性: 一次性来多个 (同时 执行多个事务)

    走到这里 我们 写 上了 锁 ,读 也上了锁,那么是不是就没有问题了,错 其实 我们还 会 遇到 幻读的问题。

    下面我们继续,来看一下幻读 问题。

    5.幻读 问题

    在这里插入图片描述


    在这里插入图片描述

    这里 : 事务 虽然 在提升 隔离性的时候 要进行一系列的加锁,但这个锁也不是 把整个数据库给锁定了,还是可以改 其他表的,甚至说改这个表的其他的行。

    对于我们 在 不可修改状态下写 另外 一篇 博客 的情况下,这里虽然提高了并发性 , 但是 这里就会带来 另外一个问题。

    本来只有 一篇 博客,现在 又 多了 一篇 博客,变成了 2 ,我们 读到的 文章个数 变多,这里我们将文章数目变多 (或变少)称为幻读问题。

    幻读问题 :一个事务执行过程中进行 多次查询,多查询的结果集不一样(多了一条 或 少了一条),这个操作,算是一种特殊的不可重复读

    那么 如何 解决 幻读问题 呢?

    6.幻读问题的处理方式


    解决幻觉问题: 彻底串行化执行。

    啥意思呢?

    其实 就是 ,读者在读博客的时候, 作者 啥事都不要干,直接摆烂。等读者读完,作者才开始卷。( 一个事务 完成了才能 执行下一个事务)。

    这种做法 ,隔离性 最高,并发 程度 最低 ,数据最可靠,速度最慢。

    最后 你能 总结 一下 并发 和 隔离吗?

    答: 并发性 能够 让事务的执行速度快,但 难以 确定 事务的准确性。

    ​ 隔离 性 能够 让事务的准确性提高,但 会降低 事务的 执行速度, 一次性只能执行一个,哪能 与 人家 一次性 执行多个相比呢。

    ​ 这里 并发 和 隔离 是 不能 兼得,我们就需要 根据实际需要来调整数据库的隔离级别, 通过 不同的隔离级别, 也就控制了 事务之间的隔离性, 也 控制了并 发程度。

    谈到隔离级别 我们 就来了解 一下MySQL 中 事务的隔离级别。

    MySQL 中 事务 的隔离级别

    MySQL 中 事务 的隔离级别,提高了这么几种

    1.read uncommitted : 允许读取未提交的数据,并发程度最后,隔离程度最低,会引入脏读问题 + 不可重复读 问题 + 幻读问题。



    2.read committed : 只允许 读取提交之后的数据,相当于对 写操作 加锁, 并发程度 降低 一些, 隔离程度提高了一些,解决了脏读 问题 但是 会引入 不可重复读 问题+ 幻读 问题、

    3.repeatable read : 相当于给 读 和 写 都加锁, 并发程度又降低了, 隔离程度 又提高了,解决了 脏读 和 不可重复 读 问题 ,但 会 引入 幻读问题。


    4.serializable : 串行化 。 并发程度 最低 (串行执行),隔离 程度 最高, 解决了脏读, 不可重复 ,幻读等问题 但 执行 速度 最慢。

    上面 : 这里些 操作 都可以通过 my.ini 这个 配置文件,来设置当前的隔离级别。

    这里 我们就可以 通过 实际 需求 场景,来 决定使用那种隔离级别。

    到此 事务 就 讲完了, 这里如果 面试 中 ,被问到了 回答

    事务的 四个基本的特性即可(重点 就在于 隔离性)。

    如何 对 查询 当前 服务器数据库 的隔离级别 于设置当前的 隔离级别的指令 感兴趣可自行上网百度。

    幻读问题。

    2.read committed : 只允许 读取提交之后的数据,相当于对 写操作 加锁, 并发程度 降低 一些, 隔离程度提高了一些,解决了脏读 问题 但是 会引入 不可重复读 问题+ 幻读 问题、

    3.repeatable read : 相当于给 读 和 写 都加锁, 并发程度又降低了, 隔离程度 又提高了,解决了 脏读 和 不可重复 读 问题 ,但 会 引入 幻读问题。

    4.serializable : 串行化 。 并发程度 最低 (串行执行),隔离 程度 最高, 解决了脏读, 不可重复 ,幻读等问题 但 执行 速度 最慢。


    上面 : 这里些 操作 都可以通过 my.ini 这个 配置文件,来设置当前的隔离级别。

    这里 我们就可以 通过 实际 需求 场景,来 决定使用那种隔离级别。

    到此 事务 就 讲完了, 这里如果 面试 中 ,被问到了 回答

    事务的 四个基本的特性即可(重点 就在于 隔离性)。

    如何 对 查询 当前 服务器数据库 的隔离级别 于设置当前的 隔离级别的指令 感兴趣可自行上网百度。

  • 相关阅读:
    ClickHouse 对付单表上亿条记录分组查询秒出, OLAP应用秒杀其他数据库
    c++之旅第七弹——继承
    C语言中常用的字符串处理函数(strlen、strcpy、strcat、strcmp)
    MySQL数据库——第五节 — MySQL索引事务
    Linux编译安装libmodbus库
    网络安全工程师需要学什么?零基础怎么从入门到精通,看这一篇就够了
    获取一段程序运行的时间
    vue3中hooks的介绍及用法
    Vue.js核心技术解析与uni-app跨平台实战开发学习笔记 第10章 Vuex状态管理 10.7 Vuex实例之登录退出
    TikTok英国站的热门标签(二)
  • 原文地址:https://blog.csdn.net/mu_tong_/article/details/126107007