MySQL-InnoDB锁(一)
本文主要记录InnoDB存储引擎中锁的关键点,下篇文章通过实例确认加锁的范围。
InnoDB中的锁
1. 锁提供数据完整性和一致性
2. InnoDB行级锁:共享锁(S)和排他锁(X)。
为了支持多粒度锁定,InnoDB支持意向锁,该锁允许事务在行锁和表锁同时存在。包括意向共享锁(IS,为某些记录加意向共享锁)和意向排他锁(IX,为某些记录加意向排他锁)。
意向锁将锁定的对象分为多个层次,意味着事务希望在更细粒度上进行加锁,如需要对页上的记录r加X锁,分别需要对数据库、表、页加意向锁IX,最后对记录r加X锁,其中任何一部分导致等待,该操作需要等待粗粒度锁的完成。
3. 锁的查看方式
通过show engine innodb status来查看,其中的transactions片段可以看到事务,其中包括锁等待。
在information_schema架构下,有3个表记录了事务和锁相关的信息。分别是INNODB_TRX,INNODB_LOCKS,INNODB_LOCK_WAITS。(具体看书或博客)
4. 一致性非锁读
非锁定读机制,是InnoDB存储引擎的默认设置,默认读取不会占用和等待表上的锁
InnoDB存储引擎利用行多版本控制实现一致性非锁读,
当读取的行正在加X锁DELETE或UPDATE时,读操作不会等待锁释放,会读取行的一个快照数据
快照数据是指该行之前版本的数据,其通过undo段完成的,因为undo用于事务中回滚数据,因此快照数据没有额外的开销,并且读快照也不需要加锁
每行记录可能有多个版本的快照,由此带来的并发控制,称为多版本并发控制(Multi Version Concurrency Control,MVCC)。
在READ COMMIT事务隔离级别下,非锁一致性读总是读取被锁定行的最新一份快照数据,故可能会读到其他事务的提交,违反了ACID的隔离性
在REPEATALE READ事务隔离级别下,非锁一致性读总是读取事务开始时的行数据版本
5. 一致性锁定读
除了默认非锁定一致性读,还可以显式加锁读,有2种一致性锁定读:
SELECT .... FOR UPDATE 加IX锁
SELECT .... LOCK INSHARE MODE 加IS锁
6. 自增长与锁
对含有自增长值的表都有一个自增长计数器,插入时根据该自增长计数器加1赋予该增长列,通过AUTO-INC Locking实现,其为特殊的表锁机制
并发插入时,该方式性能较差,一个事务需要等待另一个事务而阻塞
5.1.22版本后,InnoDB提供了一种轻量级互斥量的自增长实现机制,提高插入性能
InnoDB通过innodb_autoinc_lock_mode参数控制自增长模式,值有0\1\2
自增长值的列必须是索引,同时必须是索引的第一个列
7. 外键和锁
对一个外键列,如果没有显式对该列加索引,InnoDB会自动为其加一个索引,可以避免表锁(锁是对索引进行锁定的)
对于外键值的插入或更新是首先需要查询父表中的记录,即SELECT 操作,会为父表的记录使用SELECT....LOCK IN SHARE MODE加一个S锁。而不是使用一致性非锁定读的方式,因为该方式在读取时可能读到的是行记录的快照,如果父表同时更改该记录,可能会发生数据不一致的问题。
如事务A中父表删除记录r(加X锁,未提交),事务B插入引用父表记录r的行
若在父表加S锁,碰到父表已经加了X锁,则事务B阻塞等待;
若使用一致性非锁定读,并在REPEATABLE READ事务隔离级别下,可以读到父表中的r记录,事务B插入成功。
等到事务A提交后,就会出现父、子表数据不一致的情况。
锁的算法
1. InnoDB支持行级锁,还支持范围锁。有3种行锁实现:
Record Lock:单行锁,锁住索引记录,如果表没有建立索引,会使用隐式的主键进行锁定
Gap Lock:间隙锁,锁定一个范围,不包括记录本身。可由不同的事务共同持有,只是阻止插入(MySQL文档描述:Gap locks in InnoDB
are “purely inhibitive”, which means that their only purpose is to prevent other transactions from inserting to the gap. Gap locks can co-exist. A gap lock taken by one transaction does not prevent another transaction from taking a gap lock on the same gap. There is no difference between shared and exclusive gap locks. They do not conflict with each other, and they perform the same function.)
Next-Key Lock: Record Lock + Gap Lock,锁定一个范围,包括记录本身。可以解决Phantom Problem,在默认的事务隔离级别下,REPEATABLE READ 采用该锁技术。
2. Next-Key Lock 的锁机制
(1)有索引情况
当索引具有唯一属性时,
① 查具体行时,Next-Key Lock会降级为Record Lock,即仅锁住索引本身,而不是范围;
② 查小于某值时,Next-Key Lock会锁定小于该值的所有行,并锁定到下一个键值的范围;
③ 查大于某值时,Next-Key Lock会锁定大于该值的所有行,并锁定到前一个键值的范围;
当索引列为辅助索引,Next-Key Lock会为聚集索引和辅助索引分别加锁,聚集索引相等时在该索引上只加Record Lock,辅助索引正常加,聚集索引也是范围查找时,应该会加GAP锁。
两种显式关闭Next-Key Lock的方式:事务隔离级别改为READ COMMITTED;设置innodb_locks_unsafe_for_binlog为1。
(2)没有索引情况
因为没有索引键值的时候,自动隐式创建索引会锁定整个区间。但依然是行锁而不是表锁,只是等价于表锁。
锁的问题
1. 脏读
脏读,是事务读取到脏数据。脏数据是事务对缓冲池中行记录的修改,还没有被提交。如READ UNCOMMIT事务隔离级别,违反了事务隔离性。
脏页,是指事务提交后在缓冲池中已被修改的页,但还没有刷新到磁盘中,即数据库实例内存中的页与磁盘中的页数据不一致,当然当数据刷新到磁盘之前,日志都已经被写到重做日志文件中。
对脏页的读取是正常的,因为脏页的刷新是异步的,内存中和磁盘最终会达到一致性。这种方式不影响数据的可用性,还可以带来性能的提高。
2. 不可重复读(幻读)
在一个事务内两次查询得到的数据不一致的情况,为不可重复读。如READ COMMITTED事务隔离级别,违反事务一致性
在默认的事务隔离级别下,REPEATABLE READ 采用Next-Key Lock锁技术,锁定索引范围,可避免该现象。
3. 丢失更新
在READ UNCOMMIT事务隔离级别下,并发事务可以相互覆盖其他事务的更改,导致丢失更新。
死锁
死锁是只两个或两个以上的事务在执行过程中,因争夺资源而造成的一种互相等待的现象。
解决死锁方式:
① 最简单的方式是超时,当事务等待时间超过时间阈值,进行回滚。根据FIFO的顺序选择回滚对象时,若超时的事务所占权重比较大,即更新操作很多行,占用较多的undo log,回滚该事务比回滚其他事务占用时间长,该方式就不合适。
② 等待图(wait-for graph),一种主动的死锁检测方式,要求数据库存储两种信息:锁的信息链表和事务的等待链表,前者记录当前事务加锁信息,后者记录事务的等待情况。
通过这两张表可以构建一张事务等待图,当出现回路,表示存在死锁。此时,InnoDB选择回滚undo量最小的事务。
锁升级
InnoDB存储引擎不存在锁升级的问题。
其不是根据每个记录来产生行锁的,而是根据每个事务访问的每个页对锁进行管理的(通过意向锁为行记录加锁),故事务锁住页中一个记录或多个记录,锁开销是一样的。
对锁的管理是采用位图的方式(待研究),假如一张表有3 000 000(3M)个数据页,每页大约100条记录,共300 000 000条记录,若、假如一个事务对全表加X锁,若行锁根据每行记录进行锁定,每个锁占用10字节,则锁的管理就需要差不多3G内存。而InnoDB根据页加锁,采用位图的方式,假如每个页存储的锁信息占用30个字节,则所对象仅需30M的内存。
参考
《MySQL技术内幕-InnoDB存储引擎》
MySQL-InnoDB锁(一)的更多相关文章
- mysql: 关于MySQL InnoDB锁行还是锁表?
baidu zone - 关于MYSQL Innodb 锁行还是锁表,深入讲解
- mysql innodb锁简析(2)
继续昨天的innodb锁的分析: 注:此博文参考一下地址,那里讲的也很详细.http://xm-king.iteye.com/blog/770721 mysql事务的隔离级别分为四种,隔离级别越高,数 ...
- [转]关于MYSQL Innodb 锁行还是锁表
关于mysql的锁行还是锁表,这个问题,今天算是有了一点头绪,mysql 中 innodb是锁行的,但是项目中居然出现了死锁,锁表的情况.为什么呢?先看一下这篇文章. 目时由于业务逻辑的需要,必须对数 ...
- MySQL InnoDB锁机制
概述: 锁机制在程序中是最常用的机制之一,当一个程序需要多线程并行访问同一资源时,为了避免一致性问题,通常采用锁机制来处理.在数据库的操作中也有相同的问题,当两个线程同时对一条数据进行操作,为了保证数 ...
- mysql InnoDB锁等待的查看及分析
说明:前面已经了解了InnoDB关于在出现锁等待的时候,会根据参数innodb_lock_wait_timeout的配置,判断是否需要进行timeout的操作,本文档介绍在出现锁等待时候的查看及分析处 ...
- RDS MySQL InnoDB 锁等待和锁等待超时的处理
https://help.aliyun.com/knowledge_detail/41705.html 1. Innodb 引擎表行锁等待和等待超时发生的场景 2.Innodb 引擎行锁等待情况的处理 ...
- MySQL InnoDB锁机制之Gap Lock、Next-Key Lock、Record Lock解析
MySQL InnoDB支持三种行锁定方式: l 行锁(Record Lock):锁直接加在索引记录上面,锁住的是key. l 间隙锁(Gap Lock):锁定索引记录间隙,确保索引记录的间隙 ...
- 你需要知道的MySQL&InnoDB锁都在这里
目录 一.前言 二.锁的类型 2.1 全局锁 2.2 表级锁 2.2.1 表锁 2.2.2 元数据锁(Meta Data Locks) 2.2.3 自增列锁(AUTO-INC Locks) 2.2.4 ...
- mysql——InnoDB 锁
https://www.cnblogs.com/leedaily/p/8378779.html 1.InnoDB锁的实现方式:给索引项加锁,只有通过索引条件检索数据,InnoDB才使用行级锁,否则,I ...
- Mysql Innodb 锁机制
latch与lock latch 可以认为是应用程序中的锁,可以称为闩锁(轻量级的锁) 因为其要求锁定的时间必须要非常短,若持续时间长,则会导致应用性能非常差,在InnoDB存储引擎中,latch又可 ...
随机推荐
- 【多重背包】Transport Ship
[来源] 2018年焦作网络赛 [参考博客] https://blog.csdn.net/baymax520/article/details/82719454 [题意] 有N种船只,每种船只的载货量为 ...
- 简单说说utf-8编码格式
提到utf-8,脑海里立马出现了Unicode.那什么是utf-8, 什么是Unicode呢?简要说一下. Unicode(Universal Multiple-Octet Coded Charact ...
- 六一广告页H5全屏滚动效果实现
明天就六一儿童了(放假了),在这里提前祝大家周末快乐,每逢节假日公司必然会推出h5活动页的需求,这次六一儿童节也不例外,产品这次倒是没提什么互动效果需求,只不过根据UI妹子给的设计图,图片与图片中颜色 ...
- java——ArrayList中contains()方法中的疑问
问题引子: ist<Student> students=new ArrayList<Student>(); students.add(new Student("201 ...
- nop4.1用2008r2的数据库
修改appsetting.json
- Java基础第二天--多态、接口
多态 多态的概述 同一个对象,在不同时刻表现出来的不同形态 多态的前提和体现 有继承/实现关系 有方法重写关系 有父类引用指向子类对象 public class Animal { public voi ...
- O056、Extend Volume 操作
参考https://www.cnblogs.com/CloudMan6/p/5645305.html 今天学习如何扩大volume的容量,为了保护现有的数据,cinder不允许缩小volume. ...
- JavaScript笔记(3)
字典(Array对象) Array对象当字典使用时,.length属性就不能使用了 如果想访问对象元素,不能使用索引,只能使用key 如果遍历字典,只能使用for--in语句 字典是另一种可变容器模型 ...
- vue全局设置请求头 (封装axios请求)
Vue.http.interceptors.push((request, next) => { // 请求发送前的处理逻辑 request.headers.set('Authorization' ...
- haproxy实现ssl套接字加密
概述 如果你的应用使用SSL证书,则需要决定如何在负载均衡器上使用它们. 单服务器的简单配置通常是考虑客户端SSL连接如何被接收请求的服务器解码.由于负载均衡器处在客户端和更多服务器之间,SSL连接解 ...