MySQL中的锁

Posted hellohello

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL中的锁相关的知识,希望对你有一定的参考价值。

锁的粒度

技术图片

表锁:锁住整个表,加锁和释放速度快,能避免死锁。因为锁住的范围大,并发性低。

页锁:锁住的范围以及性能基于表锁和行锁之间,能支持的主要是BDB(BerkeleyDB)引擎。

行锁:以行为单位进行锁定,粒度最小,并发性高。每次获取锁和释放锁需要做的事情也更多,带来的消耗自然也就更大了。此外,行级锁定也最容易发生死锁。

锁存在升级现象,数据库可能把表中的1000个行锁升级为一个表锁。因为行锁粒度小,占用的资源多,将多个行锁升级为一个表锁,能降低资源的消耗。

共享锁和排他锁

InnoDB的行级锁分为共享锁(Shared Lock、S锁、读锁)和排他锁(Exclusive Lock、X锁、写锁)。

技术图片

意向锁

InnoBD中的意向锁是表级锁,意向锁分为共享意向锁(IS)、排他意向锁(IX)。

技术图片

一致性非锁定读(consistent nonlocking read)

InnoDB存储引擎通过多版本控制(MVVC)来读取当前数据库中的行数据。如果被读取的行正在执行DELETE或UPDATE操作,这时读取操作不会等待行上锁的释放,而会去读取行的一个快照。所以非锁定读机制大大提高了数据库的并发性。

之所以称为非锁定读,因为不需要等待访问的行上的锁的释放。快照数据是指该行的之前版本的数据,该实现是通过undo日志完成的。undo日志本身是用于事务中回滚数据的,因此快照数据是不需要额外开销的。此外,读取快照数据是不需要上锁的,因为没有事务需要对历史的数据进行修改。每行数据可能有多个版本,即可能存在多个快照数据,一般称之为行多版本技术。由此带来的并发控制,称之为多版本并发控制。

一致性非锁定读是InnoDB默认的读取方式,即读取不会占用和等待行上的锁。在事务隔离级别READ COMMITTEDREPEATABLE READ下,InnoDB使用一致性非锁定读。

然而,对于快照数据的定义却不同:

READ COMMITTED事务隔离级别下,一致性非锁定读总是读取被锁定行的最新一份快照数据。这就正如这个隔离级别的名字那样,代表能读取到其他事务中提交的数据,也就是能读取到最新的数据。

REPEATABLE READ事务隔离级别下,则读取事务开始时的行数据版本。可重复读,意味着在事务中的多次相同读取是一致的,也就是不会受其他事务提交数据的影响,所以读取到的数据始终是开始事务时的行快照。

一致性锁定读(Locking Reads)

在以上的一致性非锁定读协议中,读取数据不会对数据行进行加锁,所以其他事务仍可以对被查询的数据行执行更新和删除操作。

在某些情况下,用户可以显式加锁来改变这种默认行为。InnoDB提供了两种类型的锁定读来保证额外的安全性:

SELECT ... LOCK IN SHARE MODE::对读取的行添加S锁,其他事务可以对这些行添加S锁,若添加X锁,则会被阻塞。

SELECT ... FOR UPDATE::会对查询的行及相关联的索引记录加X锁,其他事务请求的S锁或X锁都会被阻塞。

当事务提交或回滚后,通过这两个语句添加的锁都会被释放。当处于默认的自动事务中时,由于语句很快就结束了,并且事务是自动提交的,所以几乎看到以上两个语句所带来的锁影响。

行锁算法

行锁基本的说法是锁住行,但严格来说,锁住的应该是索引记录,因为Innodb中的是以聚簇索引的方式来存储数据的,所以索引记录和行记录的含义是等价的。

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


Gap Lock:间隙锁,锁定一个范围,但不包含记录本身。为了阻止多个事务将记录插入到同一个范围内,设计它的目的是用来解决幻读问题


Next-Key Lock:结合了Gap Lock和Record Lock,锁定一个范围,并且锁定记录本身。

以上是关于MySQL中的锁的主要内容,如果未能解决你的问题,请参考以下文章

硬核!管理mysql数据库的工具

Mysql中的锁

MySQL中的锁

Mysql中的锁

mysql中的锁

MySQL中的锁