MySQL 全局锁、表锁以及行锁

1. 系统版本

MySQL 5.7.25 ubuntu 16.04

2. 全局锁

全局锁即对整个数据库实例加锁,使得整个库处于只读状态,会阻塞DML和DDL语句。
使用如下命令(简称FTWRL)可为数据库加全局锁:
flush tables with read lock;
释放全局锁命令如下:
unlock tables;
此外,在客户端异常断开后,全局锁会自动释放。

3. 表级锁

3.1 表锁

表锁用于用于为单个表加锁,表锁的类型分为读锁和写锁。

3.1.1 加表锁的命令

lock tables tb_name read/write;

3.1.2 释放锁的命令

unlock tables;

3.1.3表锁对线程的阻塞作用

当前线程(假设为线程A)对表加表锁后:
(1)不能对没有加锁的表执行DML和DDL语句;
(2)只能读加了read表锁的表;
(3)能读写加了write表锁的表。
在线程A没有释放表所前,对于后续的线程B:
(1)无法读写由其他线程(此处为线程A)加了write表锁的表;
(2)可读但无法写其他线程(此处为线程A)加了read表锁的表;
(3)可读写没有加表锁的表。

3.2 元数据锁

元数据锁(meta data lock 简称MDL) 用于确保事务执行过程中表结构的稳定。MDL在MySQL 5.5中加入。MDL会在访问一个表时自动被加上。MDL分为写锁和读锁。

3.2.1 MDL读锁

对一个表执行DML语句时,会加上MDL读锁。MDL读锁之间不互斥。

3.2.2 MDL写锁

对一个表执行DDL语句时,会加上MDL写锁。MDL写锁和MDL读锁之间、MDL写锁之间互斥。例如,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完方可执行。

4. 行锁

故名思议,行锁即对行数据行进行加锁。行锁在引擎层由n各个数据库引进行擎独自实现。因此,如MyISAM没有行锁,InnoDB则有行锁。

5 两阶段锁协议及死锁

两阶段锁协议能提高数据库的事务处理效率。结合MVCC(多版本并发控制),能提高数据库的并发性能。但两阶段协议也形成了造成死锁的可能性,也为数据库带来为解决死锁问题而产生的额外性能开销甚至是数据库崩溃。
以下说明基于MySQL的InnoDB引擎。

5.1 并发控制

并发控制主要有两种方式:锁和多版本并发控制(MVCC)。

5.1.1 锁

为事务所需涉及的表加上锁(为只需获数据的共享锁,为增删改数据的表加上排他锁),确保事务串行化,确保数据的正确性。但这影响了数据库的并发性能。

5.1.2 MVCC(多版本并发控制)

MVCC为数据库的并发性能提供了高效的解决方案。
InnoDB的MVCC的实现方式为为每一个事务赋予一个自增且唯一的transaction ID。同时为涉及到事务增删改的数据行形成一个新版本,同时赋这个新版本一个row trx_id,row trx_id的值和对应事务的transaction ID值相同。
在事务开始执行的时候,数据库会对整个库创建一个视图,对于在视图建时未提交的行数版本,该视图不可见。
注意,对于已经创建但未提交的数据版本,视会通过row trx_id以及undo log回滚数据行之前已提交的版本。

5.2两阶段锁协议(Two-Phase Locking,2PL)

两阶段锁协议指的是事务的执行分为两个阶段,分别为扩展阶段(此阶段只能创建锁而不能释放锁,即需要加锁的时候才加锁)以及收阶段只能释而不加锁)。
两阶段协保证了多个事务在并发的情况下等同于串行的执行,即事务的隔离性。

5.2 死锁形成原因

当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态,称为死锁。

5.3 死锁解决机制

(1)超时
直接进入等待,直到超时。这个超时时间可以通过参数innodb_lock_wait_timeout 来设置。
(2)死锁主动检查
发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为on,表示开启死锁检测。
注意,死锁检查会消耗额外资源,若并发的线过多,则有可能由死锁检测而消耗过多资源而导数据库崩溃。

上一篇:MySQL InnoDB count()函数


下一篇:python 数据分析基础 day1-初窥内容