mysql锁机制
Posted You295
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql锁机制相关的知识,希望对你有一定的参考价值。
mysql锁机制
mysql锁概述
锁是计算机协调多个进程或线程并发访问某一资源的机制,锁保证数据并发访问的一致性、有效性;锁冲突也是影响数据库并发访问性能的一个重要因素。锁是Mysql在服务器层和存储引擎层的的并发控制;加锁是消耗资源的,锁的各种操作,包括获得锁、检测锁是否已解除、释放锁等。
一:锁的区间划分
1.间隙锁(Gap Locks)
间隙锁是开区间的,是在一个索引记录之间的间隙上的锁。
作用:保证某个间隙内的数据在锁定的情况下不会发生任何变化。比如mysql默认级别下的可重复读(RR)。当使用某一索引来搜索唯一行的语句时,不需要间隙锁定。
2.临键锁(Next-key Locks)
临键锁是行锁+间隙锁,即临键锁是一个左开右闭的区间。Innodb的默认事务隔离级别是RR,在这种级别下,如果使用select…for update 语句,那么innodb就会使用临键锁,因此可以防止幻读;但如果就算是隔离级别是RR,如果使用的是普通的select语句,那么innodb是快照读,不会使用任何的锁,因而就无法防止幻读。
二:锁的粒度划分
1.表级锁(Table-level lock)
1)是mysql中锁定粒度最大的一种锁,表示对当前操作的整张表进行加锁。
2)innodb在使用过程中只要不通过索引检索数据时,全部都是表锁。
3)开销小,加锁快;不会出现死锁;锁定的粒度大,发生锁冲突的概率最高,并发度最低。
4)mysql在执行查询语句(SELECT)前,会自动给涉及的所有表加读锁,在执行更新操作(UPDATE,DELETE,INSERT)前,会自动给涉及到的表加写锁,这个过程一般不需要用户去干预。
2.行级锁(Record Locks)
1)是mysql锁定粒度最小的一种锁,表示只对当前操作的行进行加锁。innodb只有通过索引条件检索数据时,才会使用行级锁。
2)劣势:开销大,加锁速度慢,会出现死锁现象。
3)优势:锁的粒度小,发生锁冲突的概率低,处理并发的能力强。
3.页级锁
1)锁定粒度介于表解锁和行级锁之间的一种锁,是mysql中比较独特的一种锁定级别,在其他的数据库中并不常见。
2)获取锁定所需要的的资源开销和处理并发的能力也处于其他两种锁之间。同样也会发生死锁。
3)页级锁主要应用于innodn引擎。
三:锁的级别划分
1.共享锁(share lock ,s锁)
又称为读锁;允许一个事务去读取一行,阻止其他事务获得相同数据集的排它锁,若事务对象A对数据对象a加上 S锁,则事务A可以读a,但是不能修改a,其他的事务只能在对a加s锁而不能加x锁,直到A释放a上的锁。
2.排它锁(exclusive lock,X锁)
又称为 写锁;允许获取排它锁的事物更新数据,阻止其他事务获得相同的数据集共享和排他写锁。若事务A对数据对象a加上X锁,事务A可以读a也可以修改a,但是其他事务不能对a加任何的锁,直到A释放a上的锁。
3.意向锁
1)意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的 IS 锁。
2)意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的 IX 锁。
四:按加锁方式划分
1.自动锁
当进行一项数据库操作时,缺省情况下,系统自动为此数据库操作加上所有必要加的锁。自动锁分为3种。
1)DDL锁
用于保护数据库对象的结构,如表,索引等的结构定义。
排他DDL锁:创建,修改,删除一个数据库对象的DDL语句获得操作对象的 排它锁。
共享DDL锁:需要在数据库对象之间建立相互依赖关系的DDL语句通常需要共享获得DDL锁。
如创建一个包,过程与函数引用了不同的数据库,当编译此包时数据库的事务就获得引用表的共享DDL锁。如在使用alter table语句时,为了维护数据的完成性,一致性,合法性,该事务获得了排他DDL锁。
2.显示锁
某些情况下,需要用户显示的锁定数据库操作要用到的数据。才能使数据库操作执行的更好,显示锁是用户为数据库对象而设定的。
五:锁的使用方式划分
1.乐观锁(Optimistic Lock)
乐观锁的特点是先进行业务操作,不到万不得已不去拿锁。乐观的认为拿锁多半是会成功的,因此在进行完业务操作需要实际更新数据的最后一步再去拿锁就好了。
在数据库内部update同一行的时候是不允许并发的,即数据库每次执行一条update语句时会获得update行的写锁,直到这一行被成功更新后才释放。因此在业务操作进行前获取需要锁的数据的当前版本号,然后实际更新数据时再次对版本号确认是否与之前的相同,并更新版本号,即可确认这之间没有发生并发的修改。如果更新失败即可认为老版本的数据已经被并发修改掉二不存在了,此时认为获取锁失败,需要回滚整个业务操作并重新实现整个过程。
2.悲观锁(Pessimistic Lock)
悲观锁的特点是先获取锁,在进行业务操作,即悲观的认为获取锁是非常有可能失败的,因此要先确保获取锁成功在进行业务操作。
比较
1)乐观锁在不发生取锁失败的情况下开销比悲观锁小,但是一旦失败回滚开销则比较大,因此适合用在取锁失败概率比较小的场景,可以提升系统并发性能。
2)乐观锁还适用于一些比较特殊的场景,例如在业务操作过程中无法和数据库保持连接等悲观锁无法使用的地方。
六:全局锁
全局锁就是对整个数据库实例进行加锁操作。mysql提供了一个加全局锁的方式,命令为:flush tables with read lock,当需要让整个库处于只读状态时,就可以使用这个命令,在使用这个命令之后,其他的线程操作将会被阻塞,例如:数据的增删改,数据定义语句(建表,修改表的结构等)和更新事务的提交语句。
使用场景:做全库逻辑备份,将全库中的每个表都查出来存成文本。
弊端:1)如果在主库上进行备份,那么在备份期间都不能够执行更新,业务基本上就得停摆。 2)如果在从库上进行备份,那么在备份期间从库不能执行主库同步过来的binlog,会导致主从延迟。
七:死锁问题
1.产生原因
死锁:是指两个或者两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,他们都将无法推进下去。此时成系统处于死锁状态或者系统产生了死锁。这些永远在互相等待的事务称为死锁进程。表级锁不会产生死锁。所以想要解决死锁主要还是针对于最长用的Innodb
2.解决办法
1)超时等待:当两个事务相互等待时,一个事务的等待时间超过了阈值,就将其回滚,另外的一个事务继续进行。 -----缺点:如果回滚的事务更新了很多行,占用了较多的undo log ,那么在回滚的时候花费的时间就比另外一个正常执行的事务花费的时间还要多。
2)wait-for-graph(等待图):死锁碰撞检测,是一种较为主动的死锁检测机制,要求数据库保存锁的信息链表和事务等待链表两部分信息,通过这两部分的信息构造出一张图,在每个事务请求锁并且发生等待时都会判断是否存在回路,如果图中检测到了回路,就表明有死锁产生了,这个时候innodb存储引擎就会选择回滚undo量最小的事务。
以上是关于mysql锁机制的主要内容,如果未能解决你的问题,请参考以下文章