(第四回合)回龙观大叔狂磕mysql

2022-04-19 09:37:03 浏览数 (1)

大叔, 听说你入职了一家新公司?

大叔诧异的看了我一眼, 问你这个家伙咋知道的?

我看你的脉脉更新了啊.

年轻人你刚入职场没多久, 就别整天看脉脉了, 有这时间还不如多学习会儿呢.

image.png

大叔地铁站出行

image.png

大叔从地铁站出来, 需要打开亿通行APP, 获取到一个地铁站二维码, 扫码后对应的通道闸机就会打开.

正常情况下, 钱扣了闸机打开了,这次交易就结束了.

大叔坐地铁的场景映射到数据库有以下概念:

1.原子性

出站扣费看作一个原子.

扫码出站后扣费, 不能扣了大叔的钱, 闸机还不打开, 这样大叔肯定会跳起来的.

不扣账户的钱, 闸机自动给大叔打开, 大叔开心了, 这个地铁运营公司也不干.

2.隔离性

扫码闸机打开, 只能大叔自己通过高峰时期排队也有可能自己扫码让别人进去了(我们一般通过人工智能保证隔离性)

3.持久性

大叔乘进站和出站要有乘车记录, 我们需要将它固化下来.

4.一致性

原子性 隔离性 持久性 组成了一致性

总结

在数据库中, 我们称以上为事务(ACID), 事务是必须满足原子性、隔离性、一致性和持久性的.

一致性与其他特性的关系

一致性是基础,也是最终目的,其他三个特性(原子性、隔离性和持久性)都是为了保证一致性的 在比较简单的场景(没有高并发)下,可能会发生一些数据库崩溃等情况,这个时候,依赖于对日志的 REDO/UNDO 操作就可以保证一致性 而在比较复杂的场景(有高并发)下,可能会有很多事务并行的执行,这个时候,就很可能导致最终的结果无法保证一致性.

大叔写工作进度汇报

每周五下午, 大叔所在的小组就需要把这周的工作进度同步到 wiki 一个周报里.

因为人多集中时间写, 好多次提交都跟其他同事冲突, 大叔通过学习数据库隔离级别概念的思路解决了这个问题, 我们来看看他是怎么做的吧.

在数据库标准中有4种隔离级别:

1.未提交读

同事小王还没提交工作进度, 就被我看到了(嘿嘿~), 这种我们称为脏读问题.

2.已提交读

同事小王提交了工作进度, 又被我看到了, 这种我们称为不可重复读.

3.可重复读 (mysql默认使用隔离级别)

同事小王提交了工作进度, 但是当前我没退出编辑状态, 还是我之前读到的数据(可重复读)

但是~ 小李新增的进度咋展示出来了...(新插入数据导致幻读)

4.可串行化

上面三个方案看起来一个比一个好, 但是都有点问题, 大叔会心一笑, 心想我在学 mysql小册 时候就知道这些问题啦, 完全可以靠最高隔离级别-串行化解决

于是组内提议: 同时只有一个人可读写, 提议谁要编辑在群里说一下, 改完后再通知下一个人再操作吧, 这样就可以避免冲突.

然而串行化虽然可以避免冲突, 但是对于性能影响过大, 当通知下一个人时候, 如果下一个人迟迟不回复, 可能需要等一段时间确认会浪费一些时间.

大叔又仔细想了想, git 提交代码也是每个人同时进行, 为什么写个 wiki 这就这么费劲呢?

我们每个人基于当前自己的改动生成一个版本, 提交后与最新版本比对, 解决冲突.

mysql的多版本并发控制

MVCC,全称Multi-Version Concurrency Control,即多版本并发控制.

主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读, InnoDB 事务的可重复读和读取已提交隔离等级就是通过 mvcc undo 实现的.

还记得我们上一回合介绍的 InnoDB 行记录上隐藏了两个列为 事务trx_id 和 roll_pointer.

多个事务对 InnoDB 更改记录, 都会对应记录一条 undo日志, 每条 undo日志 也都有一个 roll_pointer 属性, 记录指向下一条 undo日志 的指针, 组成一个链表, 事务提交后 undo日志 删除.

image.png

大叔中午食堂订餐

大叔的工作地点坐落在中关村某栋大厦里, 比较幸运的是大厦负一层就有一个食堂餐厅, 中午坐电梯就可以直接到了(当然挤电梯也不容易)

上次就因为大叔点了一份鱼香肉丝盖饭, 因为商家做的时候发现没有鱼肉, 去提前采购, 导致大叔等了一个小时才吃到饭(困~).

餐厅问题1:你给餐厅一位服务员说了, 但是互相传达不到

大叔给商家想了一个办法, 每次客户的要求都要写到服务单中, 防止因服务员过于忙碌(服务崩溃)而忘了之后做的事情, 服务员只需按照服务单做事即可.

WAL(write ahead log) 预写式日志, 解决了服务崩溃数据恢复问题, 关键点在于先写日志再写磁盘, 在对数据页进行修改时, 通过将"修改了什么"这个操作记录在日志中, 而不必马上将更改内容刷新到磁盘上, 从而将随机写转换为顺序写, 提高了性能.

mysql 的 WAL 跟 redo log 是一回事, 通常是物理日志, 记录的是数据页的物理修改, 而不是某一行或某几行修改成怎样怎样, 它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)

餐厅问题2: 做到一半发现食材不够还让我等

大叔给商家说, 如果发现食材不够了, 就让撤销订单好了, 把之前的付费记录查出来退钱, 我再重新下单.

undo log用来回滚行记录到某个版本。undo log一般是逻辑日志,根据每行记录进行记录.

多个事务对 InnoDB 更改记录, 都会对应记录一条 undo日志, 可重复读的隔离级别也是利用了undo log.

image.png

餐厅问题3: 鱼香肉丝不用鱼

回龙观大叔总结

大叔终于找到了工作, 也没时间跟我聊天说话了, 当然这也是 mysql 最后一回合了, 希望大叔能够在之后的职场和生活中顺利~

0 人点赞