MySQL锁
1.前言
锁是计算机在执行多线程或线程时用于并发访问同一共享资源时的同步机制,MySQL中的锁是在服务器层或者存储引擎层实现的,保证了数据访问的一致性与有效性
MySQL锁可以按模式分类为:乐观锁与悲观锁。按粒度分可以分为全局锁、表级锁、页级锁、行级锁。按属性可以分为:共享锁、排它锁。按状态分为:意向共享锁、意向排它锁。按算法分为:间隙锁、临键锁、记录锁
2. 锁类型
2.1.全局锁
(1) 概念
全局锁就是对整个数据库实例加锁
(2) 应用场景
全库逻辑备份(mysqldump)
(3) 实现方式
MySQL 提供了一个加全局读锁的方法,命令是Flush tables with read lock (FTWRL)
当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句。
风险点:
如果在主库上备份,那么在备份期间都不能执行更新,业务基本上就能停止
如果在从库上备份,那么备份期间从库不能执行主库同步过来的binlog,会导致主从延迟
解决办法:
mysqldump使用参数--single-transaction,启动一个事务,确保拿到一致性视图。而由于MVCC的支持,这个过程中数据是可以正常更新的
2. 表级锁
(1) 概念
当前操作的整张表加锁,最常使用的 MyISAM 与 InnoDB 都支持表级锁定
MySQL 里面表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)
(2) 实现方式
表锁:lock tables … read/write;
例如lock tables t1 read, t2 write; 命令,则其他线程写 t1、读写 t2 的语句都会被阻塞。同时,线程 A 在执行 unlock tables 之前,也只能执行读 t1、读写 t2 的操作。连写 t1 都不允许,自然也不能在unlock tables之前访问其他表。
元数据锁:MDL 不需要显式使用,在访问一个表的时候会被自动加上,在 MySQL 5.5 版本中引入了 MDL,当对一个表做增删改查操作的时候,加 MDL读锁;当要对表做结构变更操作的时候,加 MDL 写锁。
(3) 风险点
参考于:www.cnblogs.com/keme/p/1106…
给一个表加字段,或者修改字段,或者加索引,需要扫描全表的数据。在对大表操作的时候,肯定会特别小心,以免对线上服务造成影响。而实际上,即使是小表,操作不慎也会出问题
sessionA:
begin;
select * from t limit 1;
2. sessionB:
select from t limit 1;
3. sessionC:
alter table t add f int;
\# 会mdl锁住
4. sessionD:
select from t limit 1;
我们可以看到 session A 先启动,这时候会对表 t 加一个 MDL 读锁。由于session B 需要的也是 MDL 读锁,因此可以正常执行
之后 session C 会被 blocked,是因为 session A 的 MDL 读锁还没有释放,而 sessionC 需要MDL 写锁,因此只能被阻塞
如果只有 session C 自己被阻塞还没什么关系,但是之后所有要在表 t 上新申请 MDL 读锁的请求也会被session C 阻塞。前面说了,所有对表的增删改查操作都需要先申请MDL 读锁,而这时读锁没有释放,对表alter ,产生了mdl写锁,把表t锁住了,这时候就对表t完全不可读写了
如果某个表上的查询语句频繁,而且客户端有重试机制,也就是说超时后会再起一个新session 再请求的话,这个库的线程很快就会爆满
事务中的 MDL 锁,在语句执行开始时申请,但是语句结束后并不会马上释放,而会等到整个事务提交后再释放。
注:一般行锁都有锁超时时间。但是MDL锁没有超时时间的限制,只要事务没有提交就会一直锁注
(4) 解决办法
首先我们要解决长事务,事务不提交,就会一直占着 MDL 锁。在 MySQL 的information_schema 库的 innodb_trx 表中,你可以查到当前执行中的事务。如果你要做 DDL 变更的表刚好有长事务在执行,要考虑先暂停 DDL,或者 kill 掉这个长事务。这也是为什么需要在低峰期做ddl 变更
标签:语句,事务,MDL,读锁,session,MySQL From: https://www.cnblogs.com/zhangyf1121/p/18287375