MySQL的并发处理机制,有MVCC及锁机制来处理,上篇简要说明了 MVCC及隔离级别:mysql的并发处理机制_上篇 ,这篇来讲说mysql下的锁。html
类型 | 说明 | 场景 |
S | 共享锁 | 针对于RS隔离级别的查询或者添加Lock in share mode的SELECT查询而产生的锁 |
X | 排它锁 | 针对于update、delete、insert操做而产生的锁 |
IS | 意向共享锁 | 表级别的锁,在添加S锁以前对表格添加IS锁 |
IX | 意向排他锁 | 表级别的锁,在添加X锁以前对表格添加IX锁 |
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
|
表格 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
|
同上
|
同上
|
表格
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
|
同上
|
同上
|
表格 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锁,期间全表堵塞UPDATE\DELETE\INSERT
|
同左
|
tb_index
|
表格的age列有索引,update过程当中
tb_index 加 表格意向锁 IX
age索引上面,age=21 行添加行锁 X
再在主键上,给id=3 这一行数据,添加行数 X
你觉得结束了!并无,这里有趣了!
还会添加两个gap lock ((9,2) ,(21,3)),((21,3), (21,25))
这里咱们单独拎出小表格来分析。
![]()
|
表格的age列有索引,update过程涉及age=7,9 两行数据
tb_index 加表格意向锁 IX
age索引上面,age=7,age=9 行添加行锁 X
再在主键上,给id=2,id=5 这一行数据,添加行数 X
同时会在索引 age的值上添加 3个 gap lock,分别为
((4,4),(7,5))、((7,5),(9,2))、((9,2),(21,3))
![]()
|
||
tb_unique_index
|
觉得跟上面的加锁范围同样,no no no
惟一索引列上 每个age都是惟一的,也就是age=21只有一个,不会再INSERT一个新的 age =21进来,故在这里不须要加gap lock,加锁状况以下:
tb_index 加 表格意向锁 IX
age=21 行添加行锁 X
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
同时会在索引 age的值上添加 3个 gap lock,分别为
((4,4),(7,5))、((7,5),(9,2))、((9,2),(21,3))
可是,范围查询添加到gap lock在其余状况下跟非惟一索引会有一些差异,能够看下表的例子。
|
update tbname set name=...
where age between 1 and 7
|
update tbname set name=...
where age between 2 and 7
|
update tbname set name=...
where age between 5 and 10
|
update tbname set name=...
where age between 15 and 50
|
|
tb_index
|
(-∞,2),(2,4),(4,7),(7,9)
|
(-∞,2),(2,4),(4,7),(7,9)
|
(4,7),(7,9),(9,21)
|
(9,21),(21,25),(25,+∞)
|
tb_unique_index
|
(-∞,2),(2,4),(4,7)
|
(2,4),(4,7)
|
(4,7),(7,9),(9,21)
|
(9,21),(21,25),(25,+∞)
|
表格 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
|
不支持快照读,全部SELECT都是当前读,全部SELECT操做都须要加S锁,除主键定值查找\惟一索引定值查找外,其余基于索引或者主键的范围查找都会添加 S GAP LOCK。并发度是四个隔离级别中性能最差的。
|
当前读,根据主键修改数据
tbname 加意向表锁 IX
id=4 加 行锁 X
|
表格的age列无索引,因此update过程当中
全表加X锁,期间全表堵塞UPDATE\DELETE\INSERT
|
同左
|
tb_index
|
表格的age列有索引,update过程当中
tb_index 加 表格意向锁 IX
age索引上面,age=21 行添加行锁 X
再在主键上,给id=3 这一行数据,添加行数 X
在age索引上 添加两个gap lock ((9,2) ,(21,3)),((21,3), (21,25))
|
表格的age列有索引,update过程涉及age=7,9 两行数据
tb_index 加表格意向锁 IX
age索引上面,age=7,age=9 行添加行锁 X
再在主键上,给id=2,id=5 这一行数据,添加行数 X
同时会在索引 age的值上添加 3个 gap lock,分别为
((4,4),(7,5))、((7,5),(9,2))、((9,2),(21,3))
|
||
tb_unique_index
|
惟一索引列上 每个age都是惟一的,也就是age=21只有一个,不会再INSERT一个新的 age =21进来,故在这里不须要加gap lock,加锁状况以下:
tb_index 加 表格意向锁 IX
age=21 行添加行锁 X
|
表格的age列有索引,update过程涉及age=7,9 两行数据
tb_index 加表格意向锁 IX
age索引上面,age=7,age=9 行添加行锁 X
再在主键上,给id=2,id=5 这一行数据,添加行数 X
同时会在索引 age的值上添加 3个 gap lock,分别为
((4,4),(7,5))、((7,5),(9,2))、((9,2),(21,3))
可是,范围查询添加到gap lock在其余状况下跟非惟一索引会有一些差异,能够看下表的例子。
|
表格 SQL
|
select * from tbname
where id=5
|
select * from tbname
where id betwee 5 and 15
|
select * from tbname
where age=21
|
select * from tbname
where age betwee 5 and 9
|
tb_no_index
|
主键定值查找
表格tbname 添加 IS 意向锁
id=5 添加 S锁
|
主键范围查找
表格tbname 添加 IS 意向锁
id=5,id=6 两行数据 添加 S锁
同时添加2个 S GAP LOCK ,分别为 ((5,7),(6,25))跟((6,25),+∞)
|
全表查找
表格 tbname 添加 IS 意向锁
因为全表查找,整个表格 再次添加 S 表锁
|
全表查找
表格 tbname 添加 IS 意向锁
因为全表查找,整个表格 再次添加S 表锁
|
tb_index
|
ix_age索引查找
表格tbname 添加 IS 意向锁
索引上 age = 21 添加 S 行锁
主键上 id=3 添加 S 行锁
同时添加 2个
S GAP LOCK ,分别为 ((9,2) ,(21,3)),((21,3), (21,25))
|
ix_age索引查找
表格tbname 添加 IS 意向锁
age索引上面,age=7,age=9 行添加行锁 S
再在主键上,给id=2,id=5 这一行数据,添加行数 S
同时会在索引 age的值上添加 3个 S gap lock,分别为
((4,4),(7,5))、((7,5),(9,2))、((9,2),(21,3))
|
||
tb_unique_index
|
ix_age索引查找
表格tbname 添加 IS 意向锁
索引上 age = 21 添加 S 行锁
主键上 id=3 添加 S 行锁
因为age列惟一,故不须要添加GAP LOCK
|
ix_age索引查找
表格tbname 添加 IS 意向锁
age索引上面,age=7,age=9 行添加行锁 S
再在主键上,给id=2,id=5 这一行数据,添加行数 S
同时会在索引 age的值上添加
2 个 S gap lock,分别为
((4,4),(7,5))、((7,5),(9,2))
|