ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

MySQL-InnoDB锁(一)

2019-08-24 17:52:02  阅读:187  来源: 互联网

标签:事务 记录 Lock 索引 InnoDB MySQL 锁定


本文主要记录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    行记录加X锁

    SELECT .... LOCK INSHARE MODE     行记录加S锁

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:间隙锁,锁定一个范围,不包括记录本身

  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/MariaDB的锁

 

标签:事务,记录,Lock,索引,InnoDB,MySQL,锁定
来源: https://www.cnblogs.com/shuimuzhushui/p/11392245.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有