InnoDB存储引擎(五)锁

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kukubao207/article/details/88886150

一、概述

锁是数据库系统区别于文件系统的一个重要特性,锁机制可以用来管理对并发资源的访问,因此有了锁之后极大地提升了读写数据。InnoDB存储引擎同时支持行锁和表锁。

二、InnoDB存储引擎中的锁

2.1 锁的类型

  • S锁和X锁是行级别的锁
    S锁:共享锁,事物获取了某行记录的S锁,就可以读取该行数据
    X锁:排他锁,事物获取了某行记录的X锁,就可以修改或者删除该行数据。
    S锁只和S锁兼容,X锁和任何锁都无法兼容。

  • 意向锁
    设计该锁的目的:为了InnoDB存储引擎支持行锁和表锁同时存在,提高性能而设计的。
    我们看看没有意向锁的情况:事物A获取了某个表某行的X锁,现在事物B想要获取该表的表锁,这时候事物B就不得不去扫描整个表,看看是不是存在某个行记录已经被上了锁,如果上了锁,也就是锁冲突的话,事物B就必须等待阻塞。在没有意向锁的情况下,要获取表锁就必须扫描整个表,这样性能是非常差的。
    有了意向锁的情况:事物A如果获取了某个行的X锁之前,会对整个表上IX锁,这样事物B想要获取该表的表锁的时候,发现该表已经上了IX锁,就不需要去扫描整个表来判断每个行是否有锁了,就可以直接阻塞等待。
    此外,意向锁互相之间是兼容的,举个例子来说,多个事物想获取某个表的不同行的行锁,都要对该表上意向锁,意向锁之间不冲突,那么只要这些事物之间的行不同,就不会阻塞。

IS锁:意向共享锁
IX锁:意向排它锁

2.2 一致性非锁定读

一致性非锁定读就是说,读某个行记录不需要等待X锁的释放,也不会给这个行加S锁,这是通过MVCC(行多版本控制)来实现的,InnoDB在Commited Read和Repeatable Read的隔离级别中采用一致性非锁定读的方式实现并发读。
MVCC会给每一行数据保持多个版本的快照,快照就是行的历史版本的数据,这个是用undo段实现的,不会占用额外的空间。
在Commited Read隔离级别下,读的是最新的一份快照。
在Repeatable Read隔离级别下,读的是事物开始时的快照。

2.3 一致性锁定读

InnoDB存储引擎对SELECT语句支持两种一致性锁定读的操作。
SELECT … FOR UPDATE (X锁)
SELECT … LOCK IN SHARE MODE(S锁)

2.4 自增长与锁

2.5 外键和锁

三、锁的算法

四、锁的问题

  • 脏读
    在read uncommitted 的隔离级别下,事物A可以读取到事物B修改的但是未commit的记录 。
  • 不可重复读
    在read committed的隔离级别下,事物A先读一次记录 ,但未提交。然后事物B修改了该记录(可以修改的原因是MVCC导致事物A不会在读的时候上S锁),事物A再次读该记录,发现两次读取数据不一致,这就是不可重复读的问题。
  • 丢失更新
    (1)事物A修改行记录r,但未提交
    (2)事物B修改行记录r,但未提交
    (3)事物A提交
    (4)事物B提交
    InnoDB会用X锁来 解决这个问题,(2)会阻塞,因为(1)给行记录r上了X锁,(2)必须等待(1)和(3)完成才能继续。
    但在现实中,可能会有一个逻辑意义上的丢失更新问题
    看如下情况。
    (1)用户A查看账户余额
    (2)用户B查看同一个账户余额
    (3)用户A修改了账户余额,更新数据库并提交。
    (4)用户B修改了账户余额,更新数据库并提交。
    这样就会导致(3)的修改被(4)覆盖掉了。
    要解决这个问题,就必须让事物的操作变成串行化,而不是并行的操作。
    也就是用户A查看账户余额那一步必须要上X锁,同样用户B查看账户余额也要上排他锁。
    就用SELECT … FOR UPDATE来上排它锁就可以了。

猜你喜欢

转载自blog.csdn.net/kukubao207/article/details/88886150
今日推荐