Panda 白话 - MySQL 事务 - ACID、隔离级别、MVCC

先奉上大佬的肩膀:

MySQL专题: 脏读、不可重复读、幻读区别

MySQL事务隔离级别和实现原理

轻松理解MYSQL MVCC 实现机制

看一遍: 哦! -> 看两遍:嗯~ -> 看三遍:哦~~ -> 写一遍 :just so so

ACID - 衡量事务的4个特性

  • A - Automacity : 原子性 - 事务不可分割,要么全部提交成功,要么全部失败回滚
  • C - Consistency - 一致性 - 事务开始前和结束后,数据库完整性约束没有被破坏
  • I - Isolation - 隔离性 - 事务间的操作是相互隔离、互补影响的
  • D - Durability - 持久性 - 事务提交后,事务所做的修改会被持久化到数据库

数据库并发事务产生问题:commit

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

事务 - 隔离级别:

  • Read unCommitted - 读未提交
  • Read Committed - 读已提交
  • Repeatable Read - 可重复读
  • Seriallizable - 串行化

在这里插入图片描述

Read unCommitted - 读未提交

  • 不加锁,纯裸奔
  • 性能最好,风险最高
  • demo : 下图
    1、事务A开启,读user表数据
    2、 事务A更新user行数据
    3、事务B开启,读user表数据,读到事务A更新的数据
    4、事务A发生异常
    5、事务A回滚
    6、事务A查询user表数据
    在这里插入图片描述
    小结:
    上图看出:
  • 事务A没毛病,要做更新动作失败了,然后回滚了,相当于啥也没干
  • 事务B不行了,读到了事务A中间状态的数据,人家回滚了根本没这个数据,那你读到的就是脏数据啊
  • 这就是事务A不靠谱,你这事没成呢就暴露出来,别人都拿你这个大饼咔咔干事了,结果你掉链子了

Read Committed - 读已提交

  • 鉴于上面的经验,这会把握一点,事务提交之后再暴露出来

  • demo :下图

    1、事务A开启,读到age = 1
    2、事务B开启,读到age = 1
    3、 事务A更新 age = 10
    4、事务B 读age, 由于事务A还未提交,所以事务B读到的 age = 1
    5、事务A提交修改
    6、事务B 读age, 由于事务A已经提交,所以事务B读到的 age = 10

在这里插入图片描述
小结:

  • 看上去一片祥和,我这事做成了再告诉你

Repeatable Read - 可重复读

  • demo :下图
    1、事务A开启,读到age = 1
    2、事务B开启,读到age = 1
    3、 事务A更新 age = 10
    4、事务A提交修改
    5、事务B 读age, 虽然事务A已经提交,事务B读到的还是 age = 1
    在这里插入图片描述
    小结:
  • 这个很读已提交来比有点神奇
  • 事务A都已经提交了修改,为什么事务B读到的还是修改前的数据呢,
  • 一会儿就知道了

可重复读会产生幻读:

  • demo :下图
    1、事务A开启,读到数据1条
    2、 事务A更新 一条数据
    3、事务B开启,插入一条数据
    4、事务B提交修改
    5、事务A 读取,读到两条数据
    6、事务A提交
    在这里插入图片描述
    小结:
  • 事务A在两次读取的数据记录数不一致,懵了,以为自己产生了幻觉

eriallizable - 串行化

  • 隔离级别最高,隔离效果最好
  • 完全解决脏读、幻读、不可重复度问题
  • 事务间单线程顺序执行,事务B必须等事务A执行完

MVCC - Multi-Version Concurrency Control : 多版本并发控制

  • 并发控制机制
  • 一般用在对数据库的并发访问
  • MySQL -> InnoDB(存储引擎) -> 支持事务 -> 多线程执行 -> 并发问题 -> 并发控制 -> MVCC
  • 通过快照(版本)实现

MySQL 的 undo log - 反向操作日志:

  • insert undo log :
    • 事务进行insert操作时产生undo log,
    • 在事务回滚时需要,
    • 事务提交后即被丢弃
  • update undo log :
    • 事务进行delete、updates操作时产生的undo log,
    • 在事务回滚、读快照时需要,
    • purge线程统一清除
  • 逻辑日志
  • delete一条记录时,undo log 会记录一条对应的insert 日志
  • update一条记录时,undo log会记录一条相反的update日志
  • 事务失败需要rollback时,可以读undo log中日志进行回滚

MVCC 通过 隐式字段 实现

mysql 在表的每条记录中都增加了三个隐式字段,如下

  • DB_TRX_ID (DataBase _TransactionRecentX_ID) - 最后修改\新增 这条记录(行)的事务ID(版本号),每当开启一个新的事务,版本号默认自增
  • DB_ROLL_PTR(DataBase _RollBack_Pointer) - 回滚指针,记录删除该条数据的事务ID
  • DB_ROW_ID - 隐含自增ID,

innoDB 默认是B+树存储结构的聚簇索引,
如果表没有主键,innoDB会默认用DB_ROW_ID 作为主键建立锁引树


innoDB 检查行数据条件:

  1. 版本号(DB_TRX_ID)<= 当前事务版本号
  2. 删除版本号(DB_ROLL_ID) > 当前事务版本号 或者 undefined

因为版本号是自增的,DB_TRX_ID 有代表最近哪个事务修改过该记录,
DB_TRX_ID <= 当前T版本号就可以确保,读到的行数据要么是当前事务前的最新修改,要么是当前事务自己修改的
DB_ROLL_ID > 当前事务版本号,可以确保事务开始前数据未被删除

Demo:

  • 我们建一张panda表
  • 开启一个事务A , 版本号为 1
  • 插入3条数据,提交
  • 结果如下
    在这里插入图片描述
    Insert
  • 又开启一个事务B,版本号自增 为 2
  • 事务B要插入一条数据
  • 结果如下
    -
    Delete
  • 又开启一个事务C,版本号自增 为 3
  • 事务C要删除id = 4 的数据
  • 结果如下
    在这里插入图片描述
    Update
start  transaction;
update panda set name='功夫' where id=2;
commit;
  • 又开启一个事务D,版本号自增 为 4
  • 事务D要更新id = 2 的数据
  • 结果如下

删除原纪录,新增一条、隐式ID自增加1

在这里插入图片描述

innoDB 默认可重复读隔离级别,怎么解决幻读的呢?

  • mysql 锁:
    • 行锁 - 一次操作锁住一行、粒度小、并发度高、可能死锁
      • 共享锁 - 读锁: 其它事务只能读、不能写,可以加读锁、不能加写锁
      • 排他锁 - 写锁: 其它事务只能读、不能写,不可以加读写锁
    • 表锁 - 一次操作锁整张表、粒度大、性能低、不会死锁
    • 间隙锁(Next-key)- 一次操作锁一个区间(几行)
  • mysql -> innoDB -> B+ 树 -> 多路平衡树 -> 叶子节点为双向链表

所以Next-key(间隙锁)就很好理解了,索引为10的行数据它的左区间(负无穷,10】,右区间(30,正无穷】都是它的next节点

  • 所以更新索引值 = 10 的数据时,会上三把锁
    • 索引值 = 10 所在行数据的一把行锁
    • 左区间 (负无穷,10】的一把间隙锁(锁几行)
    • 右区间 (30,正无穷】的一把间隙锁
      在这里插入图片描述

demo:

  1. 事务A开启,读到数据1条
  2. 事务A更新 age = 10 的一条数据
  3. 事务B开启,要插入一条age = 10数据,由于age =10 所在行及两边被加上了锁,所以事务B等待
  4. 事务A查询数据,读到更新后数据
  5. 事务A 提交修改
  6. 事务B提交
    在这里插入图片描述
    小结:
  • 事务A通 过行锁+间隙锁 成功阻止了事务B插入数据
  • 在事务A中读到的记录数是一致的,没有产生幻读
  • 如果事务B插入的age > 30的话可以成功执行
  • panda理解就是相当于ConcurrentHashMap的分段锁,我使用这片数据,那这片我上锁了,你要操作其它位置数据我不管,你得操作也影响不到我

读已提交 VS 可重复读

下班了。。。未完待续。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值