MySQL锁机制
一、锁的分类
对数据操作的类型:读锁(共享锁)、写锁(排它锁)
对数据操作对粒度:表锁、行锁
lock table mylock read,tbl_dept write; #手动增加表锁 show open tables; #查看表上加过的锁 unlock tables; #解锁 show status like 'table%'; #分析系统表锁定 #Table_locks_immediate 产生表级锁定的次数 #Table_locks_waited表级锁定争用而发生的等待次数,此值很高,说明存在严重的表级锁争用情况
二、表锁(偏读)
特点:偏向MyISAM存储引擎,开销小,加锁快,无死锁,锁定粒度大,发生锁冲突的概率最高,并发度最低。
MyISAM在执行查询语句前,会自动给涉及的所有表加读锁,在执行增删改操作前,会自动给涉及的表加写锁。
对MyISAM表加读锁,不会阻塞其他进程对同一表的读请求,但会阻塞对同一表的写请求,读锁释放才会执行其他进程的写操作
对MyISAM表加写锁,会阻塞其他进程对同一表的读和写操作,只有当写锁释放,才会执行其他的进程的读写操作。
即读锁会阻塞写,但不会阻塞读,写锁则会阻塞读和写。
建表语句
create table mylock( id int not null primary key auto_increment, name varchar(20) )engine myisam; insert into mylock(name) values('a'); insert into mylock(name) values('b'); insert into mylock(name) values('c'); insert into mylock(name) values('d'); insert into mylock(name) values('e'); select * from mylock;
三、行锁(偏写)
特点:偏向InnoDB存储引擎,开销大,加锁慢,会出现死锁,锁定粒度最小,发生锁冲突的概率最低,并发度也最高。
InnoDB:支持事务,采用了行级锁
建表语句
CREATE TABLE test_innodb_lock( a int(11), b VARCHAR(16) )ENGINE=INNODB; INSERT INTO test_innodb_lock VALUES(1,'b2'); INSERT INTO test_innodb_lock VALUES(3,'3'); INSERT INTO test_innodb_lock VALUES(4,'4000'); INSERT INTO test_innodb_lock VALUES(5,'5000'); INSERT INTO test_innodb_lock VALUES(6,'6000'); INSERT INTO test_innodb_lock VALUES(7,'7000'); INSERT INTO test_innodb_lock VALUES(8,'8000'); INSERT INTO test_innodb_lock VALUES(9,'90000'); INSERT INTO test_innodb_lock VALUES(1,'b1'); CREATE INDEX idx_test_innodb_a ON test_innodb_lock(a); CREATE INDEX idx_test_innodb_b ON test_innodb_lock(b); SELECT * from test_innodb_lock;
1、行锁定基本演示
session_02 | |
---|---|
|
关闭事务自动提交 set autocommit=0; |
UPDATE test_innodb_lock SET b='4001' WHERE a=4; | |
select * from test_innodb_lock |
事务未提交,看到4000 select * from test_innodb_lock |
事务提交 commit; |
事务提交 commit; |
select * from test_innodb_lock | select * from test_innodb_lock |
UPDATE test_innodb_lock SET b='4002' WHERE a=4; |
操作同一行,存在行锁,被阻塞 UPDATE test_innodb_lock SET b='4003' WHERE a=4; |
UPDATE test_innodb_lock SET b='4005' WHERE a=4; |
操作不同行,不存在行锁,正常执行 UPDATE test_innodb_lock SET b='90001' WHERE a=9; |
2、无索引行锁升级为表锁
session_02 | |
---|---|
UPDATE test_innodb_lock SET a=41 WHERE b=4000; |
更新不同的行操作被阻塞 UPDATE test_innodb_lock SET b='90001' WHERE a=9; |
3、什么是间隙锁:
当用范围条件而不是相等条件检索数据,并请求共享或排他锁,InnoDB会给符合条件的已有数据记录的索引项加锁。
对于键值在条件范围内但并不存在的记录,叫做“间隙”。
session_02 | |
---|---|
UPDATE test_innodb_lock SET b= ‘0629’ WHERE a>1 and a<6; |
新增操作被阻塞 INSERT INTO test_innodb_lock values (2,'2000'); |
4、如何锁定一行?
session_02 | |
---|---|
BEGIN; SELECT * from test_innodb_lock where a=8 for UPDATE; |
更新操作被阻塞 UPDATE test_innodb_lock set b='1000' where a=8; |
COMMIT; |
5、行锁分析
show status like 'innodb_row_lock%'; #Innodb_row_lock_current_waits:当前正在等待锁定的数量 #Innodb_row_lock_waits:等待总次数 #Innodb_row_lock_time:等待总时长 #Innodb_row_lock_time_avg:等待平均时长
四、页锁(了解)
开销和加锁时间介于表锁和行锁之间,
会出现死锁
锁定粒度介于表锁和行锁之间,并发度一般