MySQL表锁相关

本文深入探讨了MySQL中的表锁,包括LOCK TABLES的使用、读与读、读与写、写与写的互斥关系,以及如何查询表级锁争用情况。通过实例展示了在不同操作下,表锁对并发的影响,特别提到了MyISAM表锁的特点和避免死锁的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

表锁

LOCK TABLES:锁定表,如果表已经被其他线程锁定,则会等待,直到可以获取锁。
UNLOCK TABLES:释放线程持有的全部锁

读与读不互斥;
读与写,写与写互斥。
所以当一个线程获取读锁时,其他线程也可以获取读锁,但不能获取写锁。
当一个线程获取写锁时,其他线程不能获取读锁也不能获取写锁。

表锁使用例子

随便创建一张表
create table stu(
id smallint not null auto_increment,
name varchar(10),
primary key(id))engine=InnoDB;

并插入一些数据
insert into stu(name) values("ZhaZha"),("ZhangMin");

打开两个数据库会话,分别进行下列操作:读与读、读与写、写与写。

读与读

会话A获取读锁: lock table stu read;
会话A

然后会话B读取数据:select * from stu;
会话B

结果:会话A持有读锁不会对会话B读操作造成影响,读与读可以共用锁。

继续,

读与写

会话B插入一条数据:insert into stu(name) values("TianHang");
由于会话A还持有读锁,所以会话B进行写操作时会进入等待。
这里写图片描述

让会话A释放锁
这里写图片描述

会话A释放锁以后,几乎同时,会话B完成了插入。
注意第二行,至此会话2已结等待了6min 23.59sec,不容易。
这里写图片描述

结果:会话A持有读锁其他会话不能进行写操作,读与写互斥。

写与写

会话A获取写锁: lock table stu write;
注意会话A获取写锁后,会话A是可以进行读操作的,没冲突,没毛病。
这里写图片描述

然后会话B读取数据:select * from stu;
进入等待…..
这里写图片描述
(此处我直接Ctrl C了,接下来演示会话B的写操作)

会话B进行写操作:update stu set name="FUHANG" where id =3;
进入等待…
这里写图片描述

接下来会话A释放写锁:unlock tables;
这里写图片描述

几乎同时,Truely,会话B完成了更新操作。
注意第二行,会话B等待了5min,不容易。
这里写图片描述

结果:会话A持有写锁,其他会话不能读,也不能写,读写互斥,写写互斥。

查询表级锁争用情况

show status like 'table%';
这里写图片描述

table_locks_immediate 指的是立即获得表级锁的次数,就是请求锁没有等待,立刻就成功了。
table_locks_waited指的是不能立即获取表级锁而需要等待的次数。
但显然之前的例子中进行了多次等待,为什么此处没有waited的次数是0?

其原因是5.5新引入的metadata lock(MDL),对表的访问都需要获取MDL。在这个例子中,session 1拥有一个排他MDL,因此Session2是被锁在获取MDL的阶段。
由于MDL是在获取表锁之前,因此在session 2被lock的时,上述两个变量都不变。

[MySQL Q&A] 关于 table_lock_wait 和 table_lock_immediate   http://dinglin.iteye.com/blog/1772644

什么情况下会触发table_locks_waited?
引入MDL以后,table_locks_waited并不容易触发。除非主动lock tables t read。
我们用并发压力,两个线程分别执行update t1 set y=y+1 where id=1;各5000次。
若t1为MyISAM表,MyISAM是表锁,在并发压力下,是会导致table_locks_waited急剧增加。
而在InnoDB表,由于是行锁,因此获取表锁这个逻辑都能顺利通过,因此table_locks_waited不变。

经过实验:
- 会话A执行读锁,会话B进行写操作,table_locks_waited增加
- 会话A执行写锁,会话B进行写操作,table_locks_waited不增加

注意:对于MyISAM表,在执行SELECT前,会自动给表加读锁;在执行UPDATE、DELETE、INSERT前,会给表加写锁。

MyISAM表锁不会出现死锁
因为只有你获取到所需要的所有锁的时候,操作才能正常进行。
而且特别有意思的是:如果会话A通过Lock table语句主动的获取了某个表的锁,那么他将无法对其他表进行操作,因为会话A没有申请其他表的锁。
其实通过select或者其他操作符进行操作时,也都是一次性进行锁申请,完成释放锁。
由于MySQL不支持锁升级,所以对于会话A,只能释放然后重新申请锁。

结论:

  • 一个会话获取了读锁,其他会话可以进行读操作,可以获得读锁(执行lock table xx read),但不能获得写锁。
  • 一个会话获取了写锁,其他会话不可以读,也不可以写,只能等待。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值