MySQL锁相关

不同sql加的锁

  1. select …快照读,不加锁
  2. select … lock in share mode,当前读,加S锁
  3. select …for update,当前度,加X锁
  4. DML语句,如insert、delete、update,当前读,加X锁
  5. 常见DDL语句,如alter、create等,加表级锁,且这些语句为隐式提交,不能回滚

锁与索引息息相关,Innodb的锁实现在索引上,不是物理记录上,如果没有命中索引,无法使用行锁,将退化为表锁

mysql锁与存储引擎相关,MyIsam只支持表锁,Innodb支持表锁和行锁,此文主要也是介绍Innodb相关锁,具体包含以下七种

共享/排他锁(Shared and Exclusive Locks)

标准的行级锁(row-level locking):

  1. 事务拿到某一行记录的共享锁(S锁),才可以读这一行
  2. 事务拿到某一行记录的排它锁(X锁),才可以修改删除这一行

兼容互斥表如下:

SX
S兼容互斥
X互斥互斥

意向锁(Intention Locks)

Innodb支持多粒度锁,他允许行级锁与表级锁共存,实际应用中,Innodb使用的是意向锁。
意向锁是指,未来的某个时刻,事务可能要加共享/排他锁,先提前声明一个意向。
特点

  1. 意向锁是一个表级别的锁
  2. 意向锁分为
    意向共享锁(Intention shared lock ,IS),预示着事务有意向对某些行加共享S锁
    意向排他锁(Intention exclusive lock IX),预示着事务有意向对某些行加排他X锁
    例如 select * from test 要设置IS锁,select * from test for update 要设置IX锁
  3. 意向锁协议
    事务要获得某些行的S锁,必须先获得表的IS锁
    事务要获得某些行的X锁,必须先获得表的IX锁
  4. 意向锁仅表示意向,是比较弱的锁,意向锁之间并不互斥,可以并行,如下面表1
  5. 意向锁与共享锁/排它锁互斥,如下表2
表1ISIX
IS兼容兼容
IX兼容兼容
表2SX
IS兼容互斥
IX互斥互斥

记录锁(Record Locks)、 间隙锁(Gap Locks)、 临键锁(Next-key Locks)

select * from test where id =10;

  • 记录锁:锁定id=10这行记录,前提是id为唯一索引
  • 间隙锁:锁定一个区间,不包含记录本身
  • 临键锁:记录锁+间隙锁

例如,一个索引有对应值:5,18,50
临键锁有:(-∞,5],(5,18],(18,50],(50,+∞)

特性

  1. 普通索引使用的是临键锁
  2. 主键索引使用记录锁
  3. 对不存在的记录,使用间隙锁(和索引唯一性无关)

间隙锁的作用就是防止幻读,防止幻读的原理就是 间隙锁和插入意向锁冲突,因此在间隙锁下是无法插入数据的

插入意向锁(Insert Intention Locks)

插入意向锁是间隙锁的一种,也是实施在索引上,是专门针对insert操作的
多个事务,在同一个索引,同一个范围区间内插入记录时,插入位置不冲突不会阻塞彼此。

事务A往 10 与20间插入数据,不提交:
insert into test values(11,“a”);
事务B也在10 与20间插入数据,不提交:
insert into test values(12,“a”);

问题:1. 事务B会不会阻塞?2 .使用了什么锁?
回答:
1.事务B不阻塞
增加事务C select * from test where id >10 for update 会阻塞
2.使用了插入意向锁

插入意向锁只会和间隙锁(Gap Locks)、 临键锁(Next-key Locks)冲突

recordgapnext-keyII gap
record兼容兼容
gap兼容兼容兼容
next-key兼容
II gap兼容兼容

总结

普通select

  1. 在读未提交、读已提交、可重复读这三种隔离级别下,使用的快照读,不加锁,并发非常高。
  2. 在串行化隔离级别下,普通select会升级为意向共享锁IS

select for update

select * from test where id = 1

  1. 在唯一索引上使用唯一的查询条件(id是唯一索引),会使用记录锁,即只锁定当前这行数据
  2. 在其他查询条件索引上(id为二级索引),会使用临键锁,避免索引范围区间插入记录
  3. id无索引,全表扫描,锁全表

为什么唯一索引或主键索引上只会加记录锁,而二级索引会加临建锁呢?
答:唯一索引和主键索引的约束下,都能保证查到数据只有一条,而普通索引不能保证,所以为了防止幻读,必须加间隙锁

update与delete

delete from test where id =1
update test set value = “” where id =1

  1. 在唯一索引上(id是唯一索引),只加记录锁(前提是id=1数据存在)
  2. 在二级索引上,则加临键锁,封锁索引记录前后的区间
  3. 如果update是聚焦索引的记录,则对应普通索引的记录也会隐式加锁

insert

  1. 同样是写操作,insert和delete、update不同,他会用排它锁封锁被插入的索引记录,不会封锁记录之前的范围
  2. 在插入区间加插入意向锁,但这个并不会真正的封锁区间,也不会阻止其他事务往该区间插入数据
  3. 自增索引会使用自增锁
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值