ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

MySQL的四种事务隔离级别以及MVCC

MySQL的四种事务隔离级别以及MVCC 本文实验的测试环境Windows 10cmdMySQL5.6.36InnoDB一、事务的基本要素ACID1、原子性Atomicity事务开始后所有操作要么全部做完要么全部不做不可能停滞在中间环节。事务执行过程中出错会回滚到事务开始前的状态所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体就像化学中学过的原子是物质构成的基本单位。2、一致性Consistency事务开始前和结束后数据库的完整性约束没有被破坏 。比如A向B转账不可能A扣了钱B却没收到。3、隔离性Isolation同一时间只允许一个事务请求同一数据不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱在A取钱的过程结束前B不能向这张卡转账。4、持久性Durability事务完成后事务对数据库的所有更新将被保存到数据库不能回滚。二、事务的并发问题1、脏读事务A读取了事务B更新的数据然后B回滚操作那么A读取到的数据是脏数据2、不可重复读事务 A 多次读取同一数据事务 B 在事务A多次读取的过程中对数据作了更新并提交导致事务A多次读取同一数据时结果 不一致。3、幻读系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级但是系统管理员B就在这个时候插入了一条具体分数的记录当系统管理员A改结束后发现还有一条记录没有改过来就好像发生了幻觉一样这就叫幻读。小结不可重复读的和幻读很容易混淆不可重复读侧重于修改幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行解决幻读需要锁表三、MySQL事务隔离级别事务隔离级别脏读不可重复读幻读读未提交read-uncommitted是是是不可重复读read-committed否是是可重复读repeatable-read否否是串行化serializable否否否mysql默认的事务隔离级别为repeatable-read四、用例子说明各个隔离级别的情况1、读未提交1打开一个客户端A并设置当前事务模式为read uncommitted未提交读查询表account的初始值2在客户端A的事务提交之前打开另一个客户端B更新表account3这时虽然客户端B的事务还没提交但是客户端A就可以查询到B已经更新的数据4一旦客户端B的事务因为某种原因回滚所有的操作都将会被撤销那客户端A查询到的数据其实就是脏数据5在客户端A执行更新语句update account set balance balance - 50 where id 1lilei的balance没有变成350居然是400是不是很奇怪数据不一致啊如果你这么想就太天真 了在应用程序中我们会用400-50350并不知道其他会话回滚了要想解决这个问题可以采用读已提交的隔离级别2、读已提交1打开一个客户端A并设置当前事务模式为read committed未提交读查询表account的所有记录2在客户端A的事务提交之前打开另一个客户端B更新表account3这时客户端B的事务还没提交客户端A不能查询到B已经更新的数据解决了脏读问题4客户端B的事务提交5客户端A执行与上一步相同的查询结果 与上一步不一致即产生了不可重复读的问题3、可重复读1打开一个客户端A并设置当前事务模式为repeatable read查询表account的所有记录2在客户端A的事务提交之前打开另一个客户端B更新表account并提交3在客户端A查询表account的所有记录与步骤1查询结果一致没有出现不可重复读的问题4在客户端A接着执行update balance balance - 50 where id 1balance没有变成400-50350lilei的balance值用的是步骤2中的350来算的所以是300数据的一致性倒是没有被破坏。可重复读的隔离级别下使用了MVCC机制select操作不会更新版本号是快照读历史版本insert、update和delete会更新版本号是当前读当前版本。5重新打开客户端B插入一条新数据后提交6在客户端A查询表account的所有记录没有 查出 新增数据所以没有出现幻读4.串行化1打开一个客户端A并设置当前事务模式为serializable查询表account的初始值mysql set session transaction isolation level serializable; Query OK, 0 rows affected (0.00 sec) mysql start transaction; Query OK, 0 rows affected (0.00 sec) mysql select * from account; ----------------------- | id | name | balance | ----------------------- | 1 | lilei | 10000 | | 2 | hanmei | 10000 | | 3 | lucy | 10000 | | 4 | lily | 10000 | ----------------------- 4 rows in set (0.00 sec)2打开一个客户端B并设置当前事务模式为serializable插入一条记录报错表被锁了插入失败mysql中事务隔离级别为serializable时会锁表因此不会出现幻读的情况这种隔离级别并发性极低开发中很少会用到。mysql set session transaction isolation level serializable; Query OK, 0 rows affected (0.00 sec) mysql start transaction; Query OK, 0 rows affected (0.00 sec) mysql insert into account values(5,tom,0); ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction补充1、事务隔离级别为读提交时写数据只会锁住相应的行2、事务隔离级别为可重复读时如果检索条件有索引包括主键索引的时候默认加锁方式是next-key 锁如果检索条件没有索引更新数据时会锁住整张表。一个间隙被事务加了锁其他事务是不能在这个间隙插入记录的这样可以防止幻读。3、事务隔离级别为串行化时读写数据都会锁住整张表4、隔离级别越高越能保证数据的完整性和一致性但是对并发性能的影响也越大。5、MYSQL MVCC实现机制参考链接轻松理解MYSQL MVCC 实现机制_mysql mvcc机制-CSDN博客6、关于next-key 锁可以参考链接推荐mysql锁 innodb下的记录锁间隙锁next-key锁-CSDN博客# MVCC 简单理解## 一句话**MVCC 让读和写不互相阻塞读的时候看快照写的时候改最新版各看各的。**---## 用一个生活场景理解想象一份文档很多人同时在看和改- **没有 MVCC**你正在看别人要改得等你读完读锁别人在改你得等写锁。大家排队很慢。- **有 MVCC**每个人看到的都是**自己开始读那一刻的版本快照**。别人改的是新版本不影响你手里这份旧的。你读你的他写他的互不打架。---## 三个核心角色| 角色 | 作用 ||---|---|| **隐藏字段** | 每行有两个隐藏列trx_id最后改这行的事务 ID、roll_pointer指向 undo log 的旧版本 || **undo log** | 存历史版本像一条版本链越老越靠后 || **Read View** | 事务读数据时生成的一份可见性名单决定能看到哪些版本 |---## 怎么判断我能看到哪个版本读一行时顺着 undo 版本链从新到旧找用 Read View 判断- 这个版本的事务**已提交** → 可见 ✅- 这个版本的事务**还没提交**或是我之后才开始的 → 不可见继续往旧版本找 ❌找到第一个可见的版本就是你能读到的数据。---## 两种隔离级别差别就在Read View 什么时候生成| 隔离级别 | Read View 生成时机 | 效果 ||---|---|---|| **读已提交RC** | **每次 SELECT 都重新生成** | 每次读都能看到别人最新提交的数据 || **可重复读RRMySQL 默认** | **第一次 SELECT 时生成一次之后复用** | 整个事务里读到的都一样不受别人提交影响 | 这就是为什么 RR 下可重复读——因为快照固定了。---## 和 undo log 的关系呼应前面- undo log 平时管**回滚**MVCC 场景下它多了一个身份**提供历史版本**。- 版本链就是靠 undo log 串起来的最新行 → 旧版本 → 更旧版本 → …---## 一句话收尾**MVCC 就是每行数据留着历史版本undo log 串成链每个事务拿一个可见性名单Read View顺着链找到自己能看的那版。读不加锁、写不加锁读写不阻塞。**---## 常见踩坑- ⚠️ MVCC 主要解决**读-写冲突****写-写冲突**还是靠锁。- ⚠️ RC 和 RR 的区别不是有没有 MVCC而是 **Read View 生成时机**不同。- ⚠️ 别把 MVCC 和 undo log 分开记undo log 是 MVCC 的版本来源。写博客是为了记住自己容易忘记的东西另外也是对自己工作的总结希望尽自己的努力做到更好大家一起努力进步如果有什么问题欢迎大家一起探讨代码如有问题欢迎各位大神指正给自己的梦想添加一双翅膀让它可以在天空中自由自在的飞翔
返回列表