Mysql隔离级别是如何实现的

前言

本文只是参照<MySQL是如何运行的>,总结的一些MySQL知识点,如果有未理解的内容,非常建议阅读原书!

事务并发执行时有哪些一致性问题?

  • 1.脏写:一个事务修改了另一个事务修改过的数据
  • 2.脏读:一个事务读到了另一个事务未提交的事务
  • 3.不可重复读:一个事务两次读取一行的结果不一致(期间发生了update或delete)
  • 4.幻读:一个事务同一查询多次执行的时候,由于其他事务的insert事务提交而读到不同的结果集

为了解决这些问题,就有了事务的隔离级别

- 读未提交RU:	存在2,3,4问题
- 读已提交RC:  	存在3,4问题
- 可重复读RR:	存在4问题
- 可串行化serializable:

多版本并发控制MVCC

  • 首先让我们先了解一下什么是版本链

    表中的每一条记录都有roll_pointer、trx_id两个隐藏列,每对记录进行一次改动(更新),都会产生一条undo日志(回滚的原理),每条undo日志也都有一个roll_pointer属性,通过这个属性可以将一些undo日志串联成一个链表,这个链表就是版本链

    • 什么是roll_pointer:指针,指向旧版本的数据
    • 什么是trx_id:
      • 在MySQL中每一次和数据库的交互都是一个事务,默认情况直接提交,也可以通过begin;或start transaction;语句开启事务,可以通过rollback回滚事务,commit提交事务。事务有自己的事务id
      • 另外每当一个事务,修改记录时(众所周知,innoDB存储引擎记录都存储在聚簇索引中),都把旧版本写入undo日志(通过roller_pointer串联),记录的trx_id更新为事务的id
        在这里插入图片描述
  • 我们把利用这个版本链来控制并发事务访问相同记录的行为叫做多版本并发控制MVCC

  • ReadView

    • 在ReadView包含4个属性
      • m_id:生成readView时,当前事务的活跃的读写事务的事务列表id
      • min_trx_id:生成readview时活跃的事务id的最小
      • max_trx_id:在生成ReadView时,系统应该分配给下一个事务的事务id
      • creat_trx_id:生成改ReadView的事务的事务id
    • 可见性算法:一条记录对当前事务是否可见取决于这个可见性算法
      • 当一个事务要读取记录时,如果记录版本的trx_id与ReadView的creat_trx_id相同,意味着事务在访问它自己修改过的记录,所以该版本对该事务可见
      • 如果被访问版本的trx_id小于ReadView的min_trx_id,说明,生成该版本的事务已提交,可以读
      • 如果被访问版本的trx_id大于等于max_trx_id,表明生成该版本的事务在当前事务生成ReadView后才开启,该版本对该事务不可见。
      • 如果被访问版本的trx_id在min_tx_id 到max_trx_id之间,则需要判断,当前事务是否在m_id中,如果不在,说明事务已提交,可以读,否则当前事务还活跃,不可读。

那么这些隔离级别是如何实现的呢?

  • 有两种可行的方案

    • 读用MVCC,写则加锁(并发性能好,但是无法完全解决幻读!!)
    • 读写全加锁(串行化,并发差)
  • 事务的隔离级别的实现
    事实上MVCC是读已提交RC和可重复读RR两种隔离级别的事务执行普通的Select操作时,访问记录版本链的过程.

    • 读未提交:直接读最新记录
    • 读已提交:每次读取都生成新的ReadView
    • 可重复读:只第一次读取生成ReadView
    • 序列化:所有事务加锁,串行执行

MVCC并未解决幻读

RR存在幻读

  • 事务t1,select
  • 事务t2,插入一些记录x,提交
  • 然后事务t1更新了记录x,ReadView 无法阻止t1更新和删除新插入的数据,意味着事务t2插入的记录trx_id更改成了事务t1的事务id
  • 事务t1再次select就会出现幻读
  • SQL
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ         |
+-------------------------+
1 row in set (0.00 sec)

mysql> show variables like 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select *from account where id>1;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  2 | bbb  |  1000 |
|  8 | ccc  |  1000 |
+----+------+-------+
2 rows in set (0.00 sec)
## 在这里另一个事务插入了一条数据
mysql> update account set money=1200 where id=9;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select *from account where id>1;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  2 | bbb  |  1000 |
|  8 | ccc  |  1000 |
|  9 | zff  |  1200 |
+----+------+-------+
3 rows in set (0.00 sec)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值