MySQL高级第四章——MySQL的锁机制
一、概述
1.定义
锁是计算机协调多个进程或线程并发访问某一资源的限制。
2.分类
操作类型来分:
读锁(共享锁)和写锁(排它锁)
数据粒度来分:
表锁和行锁
二、三锁
1.表锁——偏读
特点:
偏向 MyISAM 引擎,开销小,加锁快,无死锁,粒度大,并发低。
常用命令:
MyISAM在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE、DELETE、INSERT等)前,会自动给涉及的表加写锁,这个过程并不需要用户干预,因此用户一般不需要直接用LOCK TABLE命令给MyISAM表显式加锁。给MyISAM表显示加锁,一般是为了一定程度模拟事务操作,实现对某一时间点多个表的一致性读取。
查看表被锁的情况:SHOW OPEN TABLES;
//0即表示未被锁住
给表加锁:LOCK TABLE tb_name read(write) 可加读写锁(即共享锁和排它锁)
给表解锁:UNLOCK TABLES;
分析锁的情况:SHOW STATUS LIKE ‘table%’;
//分别表示产生表锁次数,以及等待锁次数
读锁
我们使用上述加锁命令显式地给某张表加读锁 :LOCK TABLE t_mylock read;这时候模拟开两个终端(s1,s2)进行模拟。(假设是是在s1中加锁)
可以发现,s1加的读锁,自己只能读这张表,不能写这张表,也不能读其他表(必须等待释放栈);
而s2由于s1开的为共享锁,可以读锁的表,也可以读其它表,但不能直接写锁住的表(必须等待s1释放锁),只能处于阻塞状态。
写锁
与加读锁类似,通过s1给t_mylock表加上写锁:LOCK TABLE t_mylock write;由于写锁是排它锁,
可以发现:s1可以读也可以写自己锁住的表(排它锁,可以为所欲为),但是自己不能读其它表(没释放,还有笔账没请呢);
s2查其它表没问题,查锁住的表同样会阻塞(被加排它锁,被锁住了)
关于表锁详细,可以参见:http://www.cnblogs.com/chenqionghe/p/4845693.html
2.行锁——偏写
特点:
偏向 InnoDB 引擎,开销大,加锁慢,有死锁,粒度小,并发高。
由此知道InnoDB 与 MyISAM的最大不同——1是支持事务,2是采用行锁。
事务的复习不在这里展开。
加锁分析:
测试环境下,关闭自动提交(SET AUTOCOMMIT=0);若s1与s2同时操作同一行记录(例如同时update),则后一个会被阻塞。
索引失效导致行锁变表锁:
之前索引章节提到的,VARCHAR类型必须必须加引号 '',例如a INT,b VARCHAR两列,b列加了索引,当执行:UPDATE t_lock SET b=1008 WHERE a=1;时,将会产生严重后果:行锁变表锁,此时在未提交的过程中(设置不自动提交)其它列的操作将会被阻塞!无法修改。
间隙锁危害:
间隙锁(Gap Lock):锁加在不存在的空闲空间,可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间。
针对的是范围的操作,例如操作 a>1 and a<6;会锁定2345,即使2并不存在
关于间隙锁的更多介绍,请参见:http://www.jianshu.com/p/bf862c37c4c9
手动锁住某一行:
SET AUTOCOMMIT=0;
BEGIN;
SELECT * FROM emp WHERE id = 1 FOR UPDATE;——锁定一行
(COMMIT)
查看行锁情况:
SHOW STATUS LIKE ‘innodb_row_lock%’;
行锁的建议: