mysql数据库的锁机制实现_【MySQL入门】之MySQL数据库的锁机制(一)

8a2f6026ba83be7190dca1805206a54f.png

一.为什么要加锁?

数据库锁机制简单来说,就是数据库在多事务并发处理时,为了保证数据的一致性和完整性,数据库需要合理地控制资源的访问规则。锁是一种资源,这个资源是和事务关联在一起的,当某个事务获取了锁,在提交或回滚之前,就一直持有该锁。

二.锁的分类

根据锁类型划分

共享锁(读锁):其他事务可以读,但不能写。

排他锁(写锁):其他事务不能读取,也不能写。

根据加锁的范围划分

全局锁、表锁和行锁三类。

全局锁

全局锁就是对整个数据库实例加锁。当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句。全局锁的典型使用场景是,做全库逻辑备份。

全局锁的命令:

Flush tables with read lock

表锁

MySQL 中表级别的锁有三种:表锁、意向锁和元数据锁(meta data lock,MDL)。

表锁的语法是 lock tables … read/write,可以用 unlock tables 主动释放锁,也可以在客户端断开的时候自动释放。

意向锁主要分为意向共享锁和意向互斥锁。

意向共享锁,事务想要给数据库某些行加共享锁,需要先给这张表加上意向共享锁。

意向互斥锁,事务想要给数据库某些行加互斥锁,需要先给这张表加上意向互斥锁。

意向锁主要是解决行锁和表锁的冲突问题。假设没有意向锁,事务A用行锁锁住其中一行,事务B申请表的互斥锁,然后修改整个表,行锁和表锁就会发生冲突,事务B想知道事务A锁住了哪一行,就需要遍历整张表,这是一个非常耗时的操作。引入意向锁之后,事务A在加行锁之前先给表加上意向锁,这样如果事务B来获取表锁,需要先判断表上是否有意向锁,如果有意向锁则阻塞,等待事务A的锁释放。

MDL(metadata lock)是用来保护表的元数据信息的,不需要显式使用,在访问一个表的时候会被自动加上,MDL的作用是维护数据的一致性,主要解决DML和DDL操作之间的一致性问题。

行锁

MySQL 的行锁是在引擎层由各个引擎自己实现的。但并不是所有的引擎都支持行锁,比如MyISAM 引擎就不支持行锁。不支持行锁意味着并发控制只能使用表锁,对于这种引擎的表,同一张表上任何时刻只能有一个更新在执行,这就会影响到业务并发度。InnoDB 是支持行锁的,这也是 MyISAM 被 InnoDB 替代的重要原因之一。

行锁又分为三种,单个行记录的锁(record lock)、间隙锁(GAP Lock)、记录锁和间隙锁的组合(next-key Lock)。

三.MDL锁

为什么要引入MDL锁?

MySQL5.5引入了meta data lock,简称MDL锁,属于表锁范畴。MDL 的作用是,保证读写的正确性。你可以想象一下,如果一个查询正在遍历一个表中的数据,而执行期间另一个线程对这个表结构做变更,增加了一列,那么查询线程拿到的结果跟表结构对不上,肯定是不行的。因此,当对一个表做增删改查操作的时候,加 MDL读锁;当要对表做结构变更操作的时候,加 MDL 写锁。读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查。读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性。

元数据锁的使用场景模拟

会话A:

mysql> begin;

Query OK, 0 rows affected (0.00 sec)

mysql> select count(1) from table_test;

+----------+

| count(1) |

+----------+

| 2439392 |

+----------+

1 row in set (7.46 sec)

会话B:

mysql> begin;

Query OK, 0 rows affected (0.00 sec)

mysql> alter table table_test add age int not null;

会话C:

mysql> show processlist;

+----+------+-----------+--------+---------+------+---------------------------------+---------------------------------------------+

| Id | User | Host | db | Command | Time | State | Info |

+----+------+-----------+--------+---------+------+---------------------------------+---------------------------------------------+

| 3 | root | localhost | gmdpdb | Sleep | 235 | | NULL |

| 6 | root | localhost | gmdpdb | Sleep | 138 | | NULL |

| 7 | root | localhost | gmdpdb | Query | 3 | Waiting for table metadata lock | alter table table_test add age int not null |

| 8 | root | localhost | NULL | Query | 0 | starting | show processlist |

+----+------+-----------+--------+---------+------+---------------------------------+---------------------------------------------+

4 rows in set (0.00 sec)

通过会话C可以看出会话B被阻塞,这是由于会话A拿到了table_test表的元数据读锁,会话B想申请table_test表的元数据写锁,由于读写锁互斥,会话B需要等待会话A释放元数据锁才能执行。

元数据锁可能带来的问题

Session A

Session B

Session C

begin;

select * from t;

alter table t add age int;

select * from t;

我们可以看到 session A会对表 t 加一个 MDL 读锁,之后 session B要加MDL写锁会被 blocked,因为 session A 的 MDL 读锁还没有释放,而 session C要在表 t 上新申请 MDL 读锁的请求也会被 session B 阻塞。前面我们说了,所有对表的增删改查操作都需要先申请MDL 读锁,就都被阻塞,等于这个表现在完全不可读写了。

077698c9edc178026832416836f26038.png

9d255f94fe21c9442b0b52dc3b2e61e5.png

e08e45f6553e36d19d2a2308bba55c45.png

愉快的每一天

文章来源: blog.51cto.com,作者:MySQL技术栈,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.51cto.com/15018708/2557501

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值