有专业做网站的吗,易语言怎么把网站音乐做进去,网页制作素材ps文件,阜宁网站开发目录
1. 什么是 MVCC#xff1f;
2. MVCC 的好处#xff1f;
3. 快照读#xff1f;当前读分别是什么#xff1f;怎么理解#xff1f;
3.1 快照读
3.2 当前读
4. 数据库的四种隔离级别
5. MVCC 实现原理
5.1 隐藏字段
5.2 undo log(版本链)
5.3 readView
6. re…目录
1. 什么是 MVCC
2. MVCC 的好处
3. 快照读当前读分别是什么怎么理解
3.1 快照读
3.2 当前读
4. 数据库的四种隔离级别
5. MVCC 实现原理
5.1 隐藏字段
5.2 undo log(版本链)
5.3 readView
6. readView 深层详解
7. MVCC中是如何解决不可重复读的
8. 间隙锁解决幻读问题(补充点) 1. 什么是 MVCC
MVCC 英文全称叫 Multiversion Concurrency Control翻译过来就是 多版本并发控制。在 MySQL 众多存储引擎中只有 InnoDB 中实现了 MVCC 机制。 2. MVCC 的好处
首先我们要清楚在 InnoDB 存储引擎下假设事务A我们对一行数据进行修改操作是会对这一行数据进行加写锁的如果此时事务B来查询这一行数据它就要加读锁读锁与写锁冲突所以十五B、加锁不成功它就必须等待事务A操作执行完毕释放写锁之后才能去进行读操作。
而有了 MVCC 的加入我们的事务B再去查询该行数据时就不需要等待事务A释放锁可以直接查询查询方式是快照读(下面会解释到)查询到的是事务A修改数据之前当前行的数据提高了数据库的并发效率。
总之一句话MVCC 是通过数据行的多版本管理来实现数据库的并发控制提高数据库的并发性能。 3. 快照读当前读分别是什么怎么理解
3.1 快照读
我们姑且把刚才的事务A的查询操作理解为写操作事务B的查询操作理解为读操作在 MVCC 下这里的读指的是快照读。了解在 Linux 操作系统和 Git 代码管理的大致应该清楚我们可以通过 Linux 操作系统的快照将系统回溯到之前的某个版本Git 也可以通过回溯版本返回至之前的某个代码版本。MVCC 中的快照与这两者大致意思相近可以类比理解。
数据在修改之前和修改之后版本是不一样的我们读取别人正在操作的数据时可以读取该数据操作之前的快照就可以避免读写锁互斥导致阻塞等待这一现象。
3.2 当前读
当前读就很好理解了没有 MVCC 时数据库是靠加锁来避免数据安全性问题加的锁都是悲观锁。共享锁排它锁都属于是当前读的一种范畴。
我们去读取数据读取到的一定是当前数据没有数据版本这一说法。假设要去读一个正在被修改的数据是会阻塞的只有别人修改完才能去执行当前读这一操作也可以理解为同步读。 4. 数据库的四种隔离级别
数据库有四种隔离级别。它们的隔离级别由低到高并发能力由高到低。
没有 MVCC 的情况下
读未提交解决了脏写问题
读已提交解决了脏写脏读问题
可重复读解决了脏写脏读不可重复读
串行化 解决了脏写脏读不可重复读幻读所有问题
在有 MVCC 的情况下
可重复读解决了脏写脏读不可重复读幻读所有并发问题。数据库默认采用的也是可重复读解决幻读正是因为采用了 MVCC 。
读已提交和可重复读的读数据方式采用的都是快照读的方式。读未提交则不可以因为读未提交独到的就是最新的数据无法使用快照串行化也不可以因为加锁的缘故也无法使用快照。 5. MVCC 实现原理
MVCC 实现原理主要依赖于三部分隐藏字段undo log版本链readView。
5.1 隐藏字段
对于 InnoDB 存储引擎的表来说它的聚簇索引记录(理解为每行数据即可)中都会有两个必要的隐藏字段 trx_id(事务id) 和 roll_pointer(回滚指针)。没有主键的表会有第三个额外的隐藏主键字段。隐藏字段的主要作用就是对每次数据操作进行标记区分并记录操作之前的数据的地址。
我就以下面这幅图来给各位解析一下 trx_id 和 roll_pointer. trx_id每次一个事务对聚簇索引的记录做改动都会把该事务的事务id赋值给隐藏字段。
roll_pointer每次对聚簇索引的记录做改动时都会把旧的版本写入到 undo 日志中去然后这个隐藏列相当于一个指针可以通过它来找到该记录修改之前的数据。
如上图假设与四个事务ABCD。事务A插入数据事务BCD均对插入的数据做了修改。四个事务在对数据进行增删改查的时候数据库就会给这四个事务的隐藏字段 trx_id 以自增的方式赋值这里 假设分别赋值为 1234。
roll_pointer 回滚指针则是指向当前数据修改之前的数据值倘若事务回滚就会返回到之前的数据。
5.2 undo log(版本链)
如上所示四个事务进行的四次数据更新操作每次数据操作之后数据库都会把操作之前的旧值存放到 undo 日志中记录下来随着更新次数的增多每次记录都会由隐藏字段中的 roll_pointer 指针连接起来形成链表所形成的链表我们就称之为版本链链表的头节点就是当前数据最新的节点。
5.3 readView
刚才我们说到了版本链既然一条数据经历了多次操作有那么多个版本我们在查询数据并进行操作的时候是怎么知道该选择哪个版本的数据的呢一定是查询操作最新的吗这是不一定的。查询操作哪个版本的数据取决于我们的第三个重要元素 readView。
readView 就是事务在使用 MVCC 机制对数据库中的数据操作时产生的读视图。当事务开启之后会生成数据库当前系统的一个快照InnoDB 会为每个事务构建一个数组用来记录并维护当前系统活跃事务的id (这里的活跃指代的是事务正在操作数据但是没有进行提交)。 6. readView 深层详解
readView 是MVCC 三个中最重要的组成部分也是面试 MVCC 时经常问道的一个点。
readView 的核心原理主要体现在 READ COMMITTD(读已提交)和 REPEATABLE READ(可重复读) 两种隔离级别上。
READ COMMITTD在每次进行 SELECT 查询操作的时候都会去生成一个 readView
REPEATABLE READ每开启一个事物才会生成一个 readView一个事务的所有SQL语句共享一个 readView。
readView 有多个属性m_ids 就可以理解为生成的数组记录如下图所示基于以下几种属性 一共有四种可能情况。 情况一 trx_id creator_trx_id说明这条记录就是当前事务插入所形成的自己插入的数据自己肯定可以访问
情况二 trx_id min_trx_id min_trx_id表示的是正在活跃的事务最小的 id而所有活跃的事物都是未提交的所以就可以查询得到不会出现读未提交的情况
情况三 trx_id max_trx_id max_trx_id表示要分配给下一个事务的 id二我们要查询的数据的 id 却比待分配的事物的 id 还要大这是不可能查得到的。
情况四 min_trx_id trx_id max_trx_id如果 trx_id 是在m_ids 中则不可以访问这个版本因为在此区间内则说明此当前事务正在进行中还没提交不能访问其他事务未提交的数据否则可能会产生脏读。如果不在m_ids 中说明当前事务已经是 commit 提交过了的则可以访问。 7. MVCC中是如何解决不可重复读的
在 MVCC 中 可重复读的隔离级别下它也解决了幻读。在 MVCC 下它是给每一个事务生成一个 readView整个事务的执行过程中用的都是同一个 readView。
举个最简单的例子如下所示 1假设现在事务A与事务B并发操作来查询 student 表事务A 执行查询操作执行查询操作之前会生成一个 readView我们姑且称之为 readView_1 事务A从始至终使用的都是 readView_1
2此时事务B来修改 student 数据又生成了一个 readView 我们称之为 readView_2然后事务B率先修改完毕并提交
3事务A在事务B提交之后才进行的查询按道理来说因为事务B修改了数据我们会产生不可重复读但是因为事务A从始至终都是用的 readView_1 所以 事务A在进行查询操作的时候查询到的其实还是事务B修改之前的数据由此就解决了不可重复读。 8. 间隙锁解决幻读问题(补充点)
刚才我已经解释过了 MVCC 中是如何解决不可重复读问题的在 InnoDB 存储引擎中幻读的问题也得到了解决解决的方式是利用间隙锁
还以下面这幅图举例说明 假设事务A与事务B并发执行事务A要查询 id 1的用户数据那么在查询之前数据库会对 id 1 之后的区间加上间隙锁也就是说在事务A执行期间其他线程不可以在 id 1 之后插入数据当有其他操作想要插入数据时会阻塞等待只有事务A执行完毕释放了间隙锁其他线程或者说事务才能进行插入操作由此就避免了幻读的产生。