MYSQL实战优化——加锁机制、数据页存储结构

2020-09-16  本文已影响0人  为爱放弃一切

MySQL是如何加锁的

我们之前讲过脏写是绝对不允许的,那么这个脏写是靠什么防止的呢?说白了,就是靠锁机制,依靠锁机制让多个事务更新一行数据的时候串行化,避免同时更新一行数据。在MySQL里,假设有一行数据在那不动,此时有一个事务来了要更新这行数据,这个时候它会先琢磨一下,看看这行数据此时有没有人加锁,一看没人加锁,此时这个事务就会创建一个锁,里面包含了自己的trx_id和等待状态,然后把锁跟这行数据关联在一起。

同时大家还记得,更新一行数据必须把它所在的数据页从磁盘文件里读取到缓存页里来才能更新,所以说,此时这行数据和关联的锁数据结构,都是在内存里的,大家要记住这一点,如下图:


lock1.jpg

既然被加锁了,此时就不能再让别人访问了。现在有另一个事务B过来了,这个事务B也想更新那行数据,此时就会检查一下当前这行数据有没有人加锁,检查之后发现被事务A加锁了,那么这个时候事务B也会加锁,然后等着排队,这个时候事务B也会生成一个锁数据结构,里面有它的trx_id,还有自己的等待状态,但是它因为是在排队等待,所以它的等待状态就是true了,意思是我在等着呢,如下图:


lock2.jpg
接着事务A这个时候更新完了数据,就会把自己的锁给释放掉,锁一旦释放了,它就会去找,此时还有没有别人也对这行数据加锁了呢?它会发现事务B也加锁了。于是这个时候,就会把事务B的锁里的等待状态修改为false,然后唤醒事务B继续执行,此时事务B就获取到锁了。

共享锁和独占锁

那么在多个事务运行的时候,它们加的是什么锁呢?其实是X锁,也就是Exclude独占锁,当有一个事务加了独占锁之后,其它事务要再更新这行数据,都是要加独占锁的,但是只能生成独占锁在后面等待。那么这个时候当其它事务读取这行数据的时候需要加锁吗?其实是不用的。因为默认情况下,有事务在更新数据的时候,然后你要去读取这行数据,直接默认就是开启mvcc机制的。也就是说,此时对一行数据的读和写两个操作默认是不会加互斥锁的,因为MySQL设计mvcc机制就是为了解决这个问题,避免频繁加锁互斥。关于mvcc机制,前面已经详细介绍过了,这里就不再赘述。

那么如果你在执行查询操作的时候就是想要加锁呢?那也是ok的,MySQL首先支持一种共享锁,就是S锁,这个共享锁的语法如下:select * from table lock in share mode,你在一个查询语句后面加上lock in share mode,意思就是查询的时候对一行数据加共享锁。如果此时有别的事务在更新这行数据,已经加了独占锁了,此时你的共享锁能加吗?当然不行了,共享锁和独占锁是互斥的,此时你这个查询就只能等着了,那么如果你先加了共享锁,然后别的事务来更新要加独占锁行吗?当然不行了,此时锁是互斥的,它只能等待。那么如果你在加共享锁的时候,别人也加共享锁呢?此时是可以的,共享锁和共享锁是不会互斥的。

表锁

表锁分为两种,一种就是表锁,一种是表级的意向锁,我们分别来看看。首先说表锁,这个表锁,可以用如下语法来加:

数据页存储结构

我们这里来介绍一下数据页存储结构,为下一章介绍索引做个前奏。
之前大家都知道,数据库最终所有的数据都是要存放在磁盘上的文件里的,然后在文件里存放的物理格式就是数据页,那么大量的数据页在磁盘文件里是怎么存储的呢?首先大家要明白的一点是,大量的数据页是按顺序一页一页存放的,然后两两相邻的数据页之间会采用双向链表的格式互相引用,大致看起来如下图所示:


datapage9.jpg

一个数据页在磁盘文件里就是一段数据,可能是二进制或者别的特殊格式的数据,然后数据页里包含两个指针,一个指针指向自己上一个数据页的物理地址,一个指针指向自己下一个数据页的物理地址。然后一个数据页内部会存储一行一行的数据,也就是平时我们在一个表里插入的一行一行的数据就会存储在数据页里,然后数据页里的每一行数据都会安照主键大小进行排序存储,同时每一行数据都有指针指向下一行数据的位置,组成单向链表。如下图:


datapage8.jpg
数据页存储就先介绍到这里,下一章介绍索引。

\color{green}{本文结束}

上一篇下一篇

猜你喜欢

热点阅读