锁是计算机协调多个进程或纯线程并发访问某一资源的机制。在数据库中,除传统的计算资源(CPU、RAM、I/O)的争用以外,数据也是一种供许多用户共享的资源。如何保证数据并发访问的一致性、有效性是所在有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。在MySQL数据库中支持多种不同粒度的锁来兼顾数据库并发与一致性问题。本文主要描述MySQL锁工作机制及其锁类型,粒度等。
一、MySQL数据库锁管理机制
SQL层实现的锁机制
Meta-data元数据锁:在table cache缓存里实现的,为DDL(Data Definition Language)提供隔离操作。一种特别的meta-data元数据类型,叫Name Lock。
表级table-level数据锁
全局读锁—FLUSH TABLES WITH READ LOCK
引擎层实现的锁机制
存储引擎特有机制—row locks行锁,page locks页锁,table locks表级,版本控制
二、锁执行流程
计算语句使用到的所有表
在每个表:打开open表—从table cache缓存里得到TABLE对象,并在此表加上meta-data元数据锁
等待全局读锁后改变数据
在每个表:锁lock表—在表加上table-level数据锁
执行语句:调用:handler::write_row()/read_rnd()/read_index()等;隐式地调用引擎级engine-level锁机制
在每个表:释放表的数据锁
在每个表:释放表的DDL锁并把表放回table?cache缓存里
DDL语句也是一样,没有典型的执行计划
三、锁粒度
共享锁(S):允许一个事务去读一行
排他锁(X):允许一个事务更新或删除一行
事务A锁住了表中的一行,让这一行只能读,不能写。之后,事务B申请整个表的写锁。如果事务B申请成功,那么理论上它就能修改表中的任意一行,这与A持有的行锁是冲突的。数据库需要避免这种冲突,就是说要让B的申请被阻塞,直到A释放了行锁。数据库要怎么判断这个冲突呢?
普通认为两步:
step1:判断表是否已被其他事务用表锁锁表。
step2:判断表中的每一行是否已被行锁锁住。但是这样的方法效率很低,因为要遍历整个表。
所以解决方案是:意向锁。
InnoDB支持多粒度锁定,这种锁定允许在行级上的锁和表级上的锁同时存在。因此InnoDB还有两种内部使用的意向锁(Intention Locks),这两种意向锁都是表级锁。用于解决表级锁和行级锁之间的冲突
意向共享锁(IS):事务打算给数据行加行共享锁,事务在给一个数据行加共享锁前必须先取得该表的IS锁。
意向排他锁(IX):事务打算给数据行加行排他锁,事务在给一个数据行加排他锁前必须先取得该表的IX锁。
间隙锁
当我们用范围条件而不是相等条件检索数据,并请求共享或排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁(NEXT-KEY)锁。
因为Query执行过程中通过范围查找的话,他会锁定整个范围内所有的索引键值,即使这个键值并不存在。
间隙锁有一个比较致命的弱点,就是当锁定一个范围键值之后,即使某些不存在的键值也会被无辜的锁定,而造成在锁定的时候无法插入锁定值范围内的任何数据,在某些场景下这可能会针对性造成很大的危害。
四、InnoDB行级锁
</div><div><div></div></div>
<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-60ecaf1f42.css" rel="stylesheet">
</div>