Mysql表锁
1. 类型
1).操作类型:
a.读锁:(共享锁):对同一个数据,多个读写操作可以同时进行,互不干扰。
b.写锁:(互斥锁):如果当前锁没有完成,则无法进行其他的读操作,写操作。
2).操作范围:
表锁:一次性对一张表整体加锁,MyISAM引擎使用,开销小,加锁快,无死锁,并发低
行锁:一次性对一条数据加锁,InnoDB引擎使用,开销大,加锁慢,有死锁,并发高
增加锁:
locak table xx read/write,table xx read/write,....;
查看加锁的表:
show open tables;
例如
## 读锁
会话1:
lock table A read; -- 给 A表 加锁;
select* from A; -- 读 A表 操作,可以
delete from A where id = 1; -- 写 A表 操作,不可以
select * from B -- 读 B表,不可以
delete from B where id = 1; -- 写 B表 操作,不可以
其他会话2:
select* from A; -- 读 A表 操作,可以
delete from A where id = 1; -- 写 A表 操作,等待 会话1 解锁;
其他会话3:
select* from B; -- 读 B表 操作,可以
delete from B where id = 1; -- 写 B表 操作,可以
会话1:
unlock tables; -- 释放锁;
*** 当 释放锁成功后,会话2 的写操作 操作成功;
## 写锁
会话1:
lock table A write; -- 当前会话,可以对当前加锁的表,进行任何操作,但是不能操其他表;
其他会话1:
对会话1中加锁的表,可以进行任何操作,但是前提是 会话1 操作完毕(解锁后);
引擎
MyISAM在执行查询前,会自动给涉及到的表加读锁,在执行更新操作前,会自动给涉及的表加写锁,所以MyISAM进行操作,会有如下情况:
a.加读锁,不会阻塞其他会话,对同一表的读锁请求,但会阻塞同一表写操作(加写锁),只有这个读锁释放后,才会执行其他写操作。
b.加写锁,会阻塞其他会话,对同一表的读和写操作,只有当写锁释放后,才会执行其他进程的读写操作
小结
分析表锁定:
查看哪些表加了锁:
show open tables; 1:代表加了锁;
分析表锁定的严重程度:
show status like 'tables%';
Table_locks_immediate:可能获取的锁的数
Table_locks_waited:需要等待的表锁数(如果值越大,说明锁竞争越大)
小结建议
Table_locks_immediate / Table_locks_waited > 5000 ,建议使用innoDB引擎,否则使用myISAM -- (遵循实际开发场景)
事物可以解任何锁
行锁: id 主键索引
**** 如果没有索引 行锁将变成表锁
会话0:
update table set name = '1' where id = '0'` -- query ok
会话1:
update table set name = '1' where id = '1'` --ok
结论:因为是行锁所以 数据不同互补干扰,索引好使
会话0
update table set name = '1' where id = 0 --ok
会话1
update table set name = '1' where id = 1 --wait
结论:因为 where 条件后 索引的类型改变了,导致索引失效(或者没索引),行锁突变成表锁导致 wait
行锁中的特殊情况:间隙锁
例如:
会话0:
顾名思义:会话0,修改 table 表 中id = 2,3,4,5,6,7,8的name的值,没有commit
当 表中没有 id = 2 这个值时,但是也加了一个锁(间隙锁),所以当 出现会话1 去操作 id = 2 时候会出现锁
当会话0 commit 后: