MySQL的并发处理机制,有MVCC及锁机制来处理,上篇简要说明了 MVCC及隔离级别,这篇来说说mysql下的锁。
温馨提示:下文有几个表格长度较长,右下角的博文导航目录会挡道,浏览时,可以点击 导航目录的左下角按钮收缩目录:
如果转载,请注明博文来源: ,版权归 博客园 苏家小萝卜 所有。望各位支持!
1 Innodb的锁
在innodb中,有4种类型的锁:IX、X、IS及S锁,其说明如下:
类型 说明 场景
S 共享锁 针对于RS隔离级别的查询或者添加Lock in share mode的SELECT查询而产生的锁
X 排它锁 针对于update、delete、insert操作而产生的锁
IS 意向共享锁 表级别的锁,在添加S锁之前对表格添加IS锁
IX 意向排他锁 表级别的锁,在添加X锁之前对表格添加IX锁
1.1 锁定兼容情况四个锁之间的兼容性,需要分成两种情况来讨论,锁粒度小于表级别的锁的兼容情况,表级的锁兼容情况。
表锁、行锁都相对好理解,这里尝试简单说明下 GAP LOCK。
假设当前隔离级别为RR,表格 tbgap( id int auto_increment primary key not null , name varchar(50) , sort int , key ix_sort (sort)) engine=innodb;
表格数据如下:
在索引ix_sort上,一共有7个间隙,分别为(-∞,(1,6)),((1,6),(2,5)),((2,5),(3,2)),((3,2),(5,4)),((5,4),(6,1)),((6,1),(7,3)),((7,3),+∞),而根据实际的隔离级别及锁申请情况,加在这些间隙上的锁,则成为 GAP LOCK 。
1.3 锁与隔离级别(不考虑 lock in shar mode跟for update ) 2 锁的申请与释放过程看SQL语句的锁情况,需要结合隔离级别、执行计划、表结构等,同一个SQL,不同的隔离级别、表结构、执行计划,其锁情况不一定是一样的!
本次模拟这3个表格,age列分别:无索引、有一般索引、有唯一索引。表结构结束及数据如下:
CREATE TABLE tb_no_index ( id int primary key not null auto_increment, age int not null, name varchar(100) );
CREATE TABLE tb_index ( id int primary key not null auto_increment, age int not null, name varchar(100) KEY ix_age(age) );
CREATE TABLE tb_unique_index ( id int primary key not null auto_increment, age int not null,name varchar(100) UNIQUE KEY ix_age(age) );
INSERT INTO tb_no_index(age) values(2),(9),(21),(4),(7),(25);
INSERT INTO tb_index(age) values(2),(9),(21),(4),(7),(25);
INSERT INTO tb_unique_index(age) values(2),(9),(21),(4),(7),(25);
每个表格IX_age的索引行数就据如下图展示:
age
2
4
7
9
21
25
id
1
4
5
2
3
6
每个表格主键上面的行数就据如下图展示:
id
1
2
3
4
5
6
age
2
9
21
4
7
25
name
null
null
null
null
null
null
2.1 Read Uncommitted
所有事务隔离级别设置: set session transaction isolation level read Uncommitted ;
RU是读未提交,不添加 LOCK IN SHARE MODE 跟 FOR UPDATE 的 SELECT 语句,均为读未提交,不加锁,存在脏读、不可重复读及幻读。
所有UPDATE、DELETE、INSERT获取当前读记录,加锁。
表格 SQL
select * from tbname
where age/id ...
update tbname set name=...
where id = 4
update tbname set name=...
where age = 21
update tbname set name=...
where age between 5 and 15
tb_no_index
读不加锁,读未提交数据
可能有脏读、不可重复读及幻读
当前读,根据主键修改数据
tbname 加意向表锁 IX
id=4 加 行锁 X
表格的age列无索引,所以update过程中,全表加X锁
支持semi-constent-read,如果有其他update语句修改其他行不堵塞,但是不支持 select ... for update
同左
tb_index
表格的age列有索引,update过程中
tb_index 加 表格意向锁 IX
age索引上面,age=21 行添加行锁 X
再在主键上,给id=3 这一行数据,添加行数 X
表格的age列有索引,update过程涉及age=7,9 两行数据
tb_index 加表格意向锁 IX
age索引上面,age=7,age=9 行添加行锁 X
再在主键上,给id=2,id=5 这一行数据,添加行数 X
tb_unique_index
同上
同上
2.2 Read Committed
所有事务隔离级别设置: set session transaction isolation level read committed ;