mysql 隐式锁和显示锁_MySQL的锁机制

(2)解锁阶段

当事务释放了一个封锁以后,事务进入解锁阶段,在该阶段只能进行解锁操作不能再进行加锁操作。

5、隐式和显示锁定

InnoDB会根据隔离级别在需要的时候自动加锁,这称为隐式加锁。另外,InnoDB也支持通过特定的语句进行显示加锁

显示加共享锁:

select  ....  lock in share mode

显示加排它锁

select  ....  for update

二、多版本并发控制(MVCC)

MySQL的大多数事务型存储引擎实现的都不是简单的行锁。基于提升并发性能的考虑,一般都实现了多版本并发控制(MVCC)。可以认为,MVCC是行锁的一个变种,但它在很多情况下避免了加锁操作,减少了开销。MVCC实现了非阻塞的读操作,写操作也只锁定必要的行。

1、MVCC的实现方式

不同的存储引擎的MVCC实现是不同的,典型的有悲观并发控制和乐观并发控制。

(1)悲观并发控制

正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制实现。在悲观锁的情况下,为了保证事务的隔离性,就需要一致性锁定读。读取数据时给加锁,其它事务无法修改这些数据。修改删除数据时也要加锁,其它事务无法读取这些数据。

(2)乐观并发控制

相对悲观并发控制而言,乐观并发控制采取了更加宽松的加锁机制。悲观并发控制大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。而乐观并发控制在一定程度上解决了这个问题。乐观并发控制,大多是基于数据版本( Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加1。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。

2、InnoDB中MVCC的实现

在InnoDB中,使用乐观并发控制来实现MVCC。在每行数据后添加两个额外的隐藏的值来实现MVCC,这两个值一个记录这行数据何时被创建,另外一个记录这行数据何时过期(或者被删除)。 在实际操作中,存储的并不是时间,而是事务的版本号,每开启一个新事务,事务的版本号就会递增。

(1)MVCC的具体操作

在可重复读事务隔离(RR)级别下,MVCC的具体操作如下:

SELECT语句

InnoDB会根据以下两个条件检查每行记录:

(a)创建版本号<=当前事务版本号

这样可以确保事务读取的行,要么在事务开始前已经存在,要么是事务自身插入或者修改过的。

(b)删除版本号为空,或者,删除版本号>当前事务版本号

这样可以确保事务读取到的行在事务开始之前未被删除。

INSERT语句

保存当前事务版本号为行的创建版本号。

DELETE语句

保存当前事务版本号为行的删除版本号。

UPDATE语句

插入一条新纪录,保存当前事务版本号为行创建版本号,同时保存当前事务版本号到原来删除的行。

通过MVCC,虽然每行记录都需要额外的存储空间,更多的行检查工作以及一些额外的维护工作,但可以减少锁的使用,大多数读操作都不用加锁,读数据操作很简单,性能很好,并且也能保证只会读取到符合标准的行,也只锁住必要行。

(2)快照读与当前读

在RR隔离级别中,通过MVCC机制,虽然让数据变得可重复读,但我们读到的数据可能是历史数据!这在一些对于数据的时效特别敏感的业务中,就很可能出问题。

对于这种读取历史数据的方式,我们叫它快照读( SNAPSHOT READ),而读取数据库当前版本数据的方式,叫当前读 (CURRENT READ)。很显然,在MVCC中:

快照读:普通的select语句。如下所示:

select * from table ....;

当前读:特殊的读操作,插入、更新、删除操作,都属于当前读,处理的都是当前的数据,需要加锁。具体如下所示:

select * from table where .... lock in share mode;

select * from table where .... for update;

insert  ....;

update  ....;

delete  ....;

事务的隔离级别实际上都是定义了当前读的级别,MySQL为了减少锁处理(包括等待其它锁)的时间,提升并发能力,引入了快照读的概念,使得select不用加锁。而update、insert这些“当前读”就需要另外的模块来解决了。

为了解决“当前读”中的幻读问题,MySQL事务使用了Next-Key锁。

(3)Next-Key锁

Next-Key锁是行锁和间隙锁的合并,行锁上文已经介绍了,接下来说下间隙锁。

间隙锁

锁加在不存在的空闲空间,可以是两个索引记录之间,也可能是第一个索引记录之前或最后一个索引之后的空间。

Next-Key锁是行锁与间隙锁的组合,这样,当InnoDB扫描索引记录的时候,会首先对选中的索引记录加上行锁,再对索引记录两边的间隙(向左扫描扫到第一个比给定参数小的值, 向右扫描扫描到第一个比给定参数大的值, 然后以此为界,构建一个区间)加上间隙锁。如果一个间隙被事务T1加了锁,其它事务是不能在这个间隙插入记录的。这样就防止了幻读,如下演示所示:

时间

账户更新事务A

账户新增事务B

T1

开始事务

T2

开始事务

T3

把所有账户的余额清0(获取行锁和间隙锁)

T4

插入一个新账户,设置余额为100

(获取不到锁,等待)

T5

等待

T6

提交事务,释放锁

等待

T8

获取锁,插入成功

T9

提交事务,释放锁

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值