浅析mysql共享锁S与排他锁X

带你认识mysql锁机制

1. InnoDB存储引擎中锁的类型

(1)共享锁 (S Lock),允许事务读一行数据

(2)排它锁 (X Lock),允许事务删除或者更新一行数据

以上两种类型的锁的都是行锁,如果事务T1已经对行r的成功加上共享锁S,那么事务T2任然可以对行r的成功加上共享锁S,

因为读取数据,而不是更新数据,这种情况称为锁兼容,但是如果事务T1对行r成功加上排它锁X,那么此时其他事务不能对

行r加任何锁,必须等待,直到T1事务在行r上的X锁释放了才可以,这种情况称为锁不兼容。

共享锁S与S兼容,排它锁X与其他锁都不兼容。

2. 锁的使用

加共享锁S

SELECT * FROM table_name WHERE 1=1 LOCK IN SHARE MODE

加排它锁X

SELECT * FROM table_name WHERE 1=1 FOR UPDATE

对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X);对于普通SELECT语句,InnoDB不会 加任何锁;事务可以通过以下语句显示给记录集加共享锁或排他锁。

InnoDB行锁是通过给索引上的索引项加锁来实现的,这一点MySQL与Oracle不同,后者是通过在数据块中对相应数据行加锁 来实现的。InnoDB这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁!

在这里插入图片描述

在如上例子中,看起来会话A只给id=2的一行加了排他锁,但会话B在请求其他行的排他锁时,却出现了锁等待!原因就是在没有索引的情况下,InnoDB只能使用表锁。

3. mysql 行锁的三种算法

InnoDB存储引擎有三种锁算法

1、Record Lock 单个行记录上的锁

2、Gap Lock 间隙锁,锁定一个范围,但不包含记录本身

3、Next-Key Lock :Gap Lock + Record Lock 锁定一个范围,并锁定本身

Record Lock 总是会去锁住索引记录,如果InnoDB存储引擎表在建立的时候没有设置任何一个索引,那么这时候会使用隐式的主键来进行锁定。

Next-Key Lock 是结合了Gap Lock 和 Record Lock 的一种锁定算法,InnoDB存储引擎对于行的查询都是采用这种锁定算法,列如一个索引有10,11,13 和 20四个值,那么该索引可能会被锁定的范围 (-∞,10], (10,11], (11,13], (13,20], (20,+∞]

这种算法的目的,正式为了解决幻读的问题(脏读、不可重复读、幻读),利用这个技术,锁定的不是单个值,而是一个范围。(下一专题专门来说说mysql隔离级别)

当然,在一些情况下,InnoDB存储引擎会对Next-Key Lock进行优化,毕竟锁住很多段范围,对性能影响还是比较大的,所以,当查询的索引含有唯一索引属性,即,唯一索引,Next-Key Lock会优化降级为Record Lock,仅锁住索引本身,而不是范围。

表名:t
|uid| name |
|-1-| a |
| 2 | b |
| 5 | c |

上表 t 中uid设置为唯一索引,

在这里插入图片描述

表中uids索引字段共有三个值,1,2,5,上面会话A首先对 uid = 5进行了X锁定,按前面的解释,此时InnoDB存储引擎应该会对行的查询采用Next-Key Lock锁定算法,锁定几段范围,但是由于uid我们设置的是唯一索引,所有会话B可以成功执行,原因就是,对锁进行了优化降级成为Record Lock,从而可以提高表的并发性能。

**

InnoDB存储引擎对Next-Key Lock的优化降级只是针对查询列是唯一索引的情况下,若是普通索引(辅助索引)则情况完全不同,我们来创建一张表

**

create table yyy (a INT,b INT,PRIMARY(a),KEY(b));
a  b
1  1
3  1
5  3
7  6

可以看出表yyy中 a是主键索引,b是辅助索引,若开启会话A执行下列SQL,

select * from yyy where b=3 for update;

根据上面的介绍,此时使用的是传统的 Next-Key Lock 算法加锁,并且由于两个索引,InnoDB会分别进行锁定,对于唯一索引或者叫聚集索引,会采用Record Lock锁定,对列a等于5的索引进行行锁锁定,对于辅助索引或者叫普通索引b等于3列,会锁定范围(1,3),需要特别注意的,InnoDB 存储引擎还会对辅助索引下一个键值加上 gap lock,即(Gap Lock + Record Lock),还有一个辅助索引范围为(3,6)的锁。 若此时,新开会话B中运行下面SQL语句,

(1) select * from yyy where a=5 in share mode;

分析:阻塞,因为a=5行已经被会话A加上排它锁:X(排它锁与共享锁不兼容)。

(2) insert into yyy (a,b)values(4,2);

分析:主键列插入 4,没问题,但是辅助索引列插入2的时候,根据上面分析,2在锁定范围(1,3)中,因此,会被阻塞等待。

(3) insert into yyy (a,b)values(6,5);

分析:主键列插入6,没有被锁定,辅助索引列5也不在锁定范围(1,3)之间,但是别忘了,另个辅助索引gap lock 范围(3,6),所以该sql还是被阻塞。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值