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 COMMITTED
和REPEATABLE 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中的锁的主要内容,如果未能解决你的问题,请参考以下文章