锁机制《mysql技术内幕InnoDB存储引擎》第六章锁机制笔记

《mysql技术内幕InnoDB存储引擎》第六章锁机制笔记

1 开发数据库驱动的时,一方面需要最大程度地利用数据库的并发访问,另一方面要确保每个用户能以一只的方式读取和修改数据,因此有了锁机制

2 数据库系统区别于文件系统的一个关键特性:锁机制

3 锁的概念:用于管理对共享文件的并发访问

4 MyISAM引擎是表锁设计 SqlServer:支持的是乐观锁和悲观锁

5 InnoDB存储引擎锁的思想和Oracal数据库非常相似,提供一致性的非锁定度,行级锁支持,行级锁没有相关额外的开销,并可以同时得到并发性和一致性

6 latch与lock都是可以被称为锁,latch被称为闩锁,轻量级的锁,因为其要求锁定的时间必须非常短,若持续的时间长,则应用的性能会非常差。在Innodb存储引擎中,latch又可以分为mutex(互斥量)和rwlock(读写锁),目的是用来保证并发线程操作临界资源的正确性,通常没有思索检验机制。

7 lock的对象是事物,用来锁定数据库中的对象,例如表,页,行,lock有死锁机制。

 

Lock

latch

对象

事物

线程

保护

数据库内容

内存数据结构

持续时间

整个事物过程

临界资源

模式

行锁,表锁,意向锁

读写锁,互斥量

死锁

通过wait-for graph,timout等机制进行死锁的检测与处理

无死锁检测与处理机制。仅通过应用程序加锁的顺序(lock leveling)保证无死锁的情况的发生

存在于

Lock Manager的哈希表中

每个数据结构的对象中

8 锁的类型

InnoDB引擎实现了以下两种标准的行级锁:

共享锁(S Lock),允许事物读一行数据

排它锁(X Lock),允许事物删除或更新一行数据

9 共享锁和排它锁的兼容性

 

X

S

X

不兼容

不兼容

S

不兼容

兼容

10 S和X都是行锁,兼容是指对统一记录(row)锁的兼容性情况

11 InnoDB存储引擎支持多粒度锁定,这种锁允许事物在行级上的锁和表级上的锁的同时存在,为了支持在不同粒度上进行加锁操作,InnoDB存储引擎支持一种额外的锁方式,称之为意向锁,意向锁是将锁定的对象分为多个层次,意向锁意味着事物希望在更细粒度上加锁。例如如果需要对也上的记录r进行上X锁,那么分别需要对该数据库,表,页上意向锁IX,最后对记录r上X锁。若其中任何一个部分导致等待,那么该操作需要等待粗粒度锁的

完成。

12 InnoDB存储引擎支持意向锁比较简单,意向锁即为表级别的锁。设计的目的主要是为了在一个事物中揭示下一行将被请求的锁类型。

13 意向锁的两种类型

意向共享锁(IS Lock),事物想要获得一张表中某几行的共享锁

意向排他锁(IX Lock),事物想要获得一张表中某机房的排它锁

InnoDB存储引擎中锁的兼容性

 

IS

IX

S

X

IS

兼容

兼容

兼容

不兼容

IX

兼容

兼容

不兼容

不兼容

S

兼容

不兼容

兼容

不兼容

X

不兼容

不兼容

不兼容

不兼容

这里的S,X指的是对整个表进行S,X上锁,我个人理解为意向锁只对某一行或几行进行加锁,意向锁和意向锁冲突的可能性不大,所以兼容

14 一致性非锁定读 指的是InnoDB存储引擎通过行多版本控制的方式来读取当前执行时间数据库中行的数据。如果读取的行正在执行delete或update操作,这时读取操作不会因此去等待行上锁的释放。相反,InnoDB存储引擎回去读取行的一个快照数据

之所以称之为非锁定读,因为不需要等待访问的行上X锁的释放。快照数据是指高行的之前版本的数据,该事项是通过undo段来完成,而undo用来在事务中回滚数据,因此快照数据本身没有额外的开销。此外,读取快照数据是不需要上锁的,因为没有事务需要对历史的数据进行修改操作。

15 InnoDB默认的是非锁定度机制,即读取不会占用和等待表上的锁。在事务的隔离级别下,读取的方式不同,对于快照的定义也不同。

16 快照数据其实就是当前数据之前的历史版本,每行记录可能有多个版本。一行记录可能有不止一个快照数据,一般称这种技术为多版本技术。由此带来的并发控制,称为多版本并发控制

17 在事务隔离级别READ COMMITED和REPEATABLE READ(InnoDB存储引擎的默认事务的隔离级别)下,InnoDB存储引擎使用非锁定的一致性读,然而,对于快照数据的定义却不同。READ COMMITED隔离级别下,对于快照数据,非一致性读总是读取被锁定行的最新一份快照数据。而在REPEATABLE READ事物隔离级别下,对于快照数据,非一致性读总是读取事物开始时的行数据版本。

18 一致性锁定度 有时候需要用户显示地对数据库读取操作进行加锁以保要求数据逻辑的一致性。而这要求数据库支持加锁语句,即使对于select的只读操作,InnoDB存储引擎对于select语句支持两种一致性的锁定读:

select ... for update 加X锁

select ...lock in share mode 加S锁

19自增长与锁 插入的数据会依据这个自增长的计数器加1赋予自增长列,这个实现方式称作Auto-INC Locking 这种锁其实是采用一种特殊的表锁机制,为了提高插入的性能,锁不是在一个事物完成后才释放,而是在完成对自增长值插入的SQL语句后立即释放

20 在InnoDB存储引擎中,自增长值得列必须是索引,同时必须是索引的第一个列,如果不是第一个列,则MySQL数据库会抛出异常。行锁的算法,分别是

Record Lock:单个行记录上的锁

Gap Lock ;间隙锁 ,锁定一个范围,但是不包含记录本身

Next-Key Lock:GapLock+RecordLock,锁定一个范围,并且包含记录本身

Gap Lock的作用是为了阻止多个事物将记录插入到同一范围内,而这会导致Phantom Problem问题的产生。用户可以通过以下两种方式来显示地关闭Gap Lock

将事物的隔离级别设置为READ COMMITTED

将参数innodb_locks_unsafe_for_binlog设置为1

在上述的配置下,除了外键约束和唯一性建仓依然需要的Gap Lock,其余情况仅适用Record Lock进行锁定,但需要牢记的是,上述设置破坏了事物的隔离性,并且对于replication,可能会导致主从数据的不一致性。此外,从性能方面来说,READ COMMITED的隔离级别美欧read repeable的隔离性高

21 解决Phantom Problem 在默认的事物隔离级别(REPEATABLE READ)下,InnODB采用Next-Key Locking机制

Phantom Problem是指在同一事物下,连续执行两次同样的SQL语句可能导致不同的的结果,第二次的SQL语句可能会返回之前不存在的行。(事物在隔离级别READ COMMITTED)下,其仅采用Record Lock

22 脏页和脏读定义 脏页指的是在缓冲池中已经被修改的页,但是还没有刷新到磁盘中,即数据实例内存中的页和磁盘中的页的数据是不一致的,当然在刷新到磁盘之前,日志都已经被写入到了重做日志文件中。

而所谓脏读数据是指事物对缓冲池中行记录的修改,并且还没有被提交

对于脏页的读取,是非常正常的。脏页是因为数据库内存和磁盘的异步造成的,这并不影响数据的一致性(或者说二者最终会达到一致,即脏页都刷回到磁盘),并且因为脏页的刷新是异步的,不影响数据库的可用性,因此可以带来性能的提高

对于脏数据,如果读到了脏数据,即一个事物可以读到另外一个事物中未提交的数据,这显然违反了数据库的隔离性

23 脏读 脏读并不常发生,发生的条件是需要事务的隔离级别为READ UNCOMMITTED,而且目前绝大部分的数据库都至少设置成READ COMMITTED.InnoDB设置的是READ REPEATABLE

脏读隔离看似毫无用处,但在一些比较特殊的情况下还是可以将事务的隔离级别设置为READ UNCOMMITIED。

24 不可重复读 在一个事物内多次读取同一数据集合。在这个事物还诶有结束时,另外一个事务也访问同一数据集合,并做了一些DML操作。因此,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的数据可能是不一样的。这样就发生了砸一个事务内两次读到的数据是不一样的情况

25 不可重复读和脏读的区别是:脏读是读到未提交的数据,而不可重复读读到的却是已经提交的数据,但是其违反了数据库事务一致性的要求

26 不可重复读的问题是可以接受的,因为其读到的是已经提交的数据,本身并不会带来很大的问题。

27在InnoDB存储引擎中,通过使用Next-key Lock算法来避免不可重复读的问题。不可重复读问题即Phantom Problem,即幻象问题。在Next-Key Lock算法下,对于索引的扫描,不仅是锁住扫描到的索引,而且还锁住这些索引覆盖的范围。因此InnoDB存储引擎的默认事务的隔离级别是READ REPEATABLE,采用了Next-Key Lock算法

28 丢失更新 一个事务的更新操作会被另一个事务的更新操作说覆盖,从而导致数据的不一致

但是,在当前数据库的任何隔离级别下,都不会导致数据库理论意义上的丢失更新问题,这是因为即使是READ UNCOMMITTED的事物隔离级别,对于行的操作,需要对行或其他粗粒度级别的对象加锁

29 在所有多用户计算机系统下都有可能产生这个问题,例如:

1>事物T1查询一行数据,放入本地内存,并显示给一个终端用户User1

2>事物T2也查询改行数据,并将取得的数据显示给终端用户User2

3>User1修改这行记录,更新数据库并提交

4>User2修改这行记录,更新数据并提交

解决问题的办法,对记录加上排它锁

30 死锁 死锁是指两个或两个以上的事务在执行过程中,因争夺锁资源而造成的一种互相等待的现象

31 解决死锁问题有一个最简单的方式,不要有等待,将任何的等待都转化为回滚,并且事务重新开始。但是在线上的环境,则可能会导致并发性能的下降,甚至任何一个事务都不能进行

32 解决死锁问题最简单的一种方法是超时,即当两个事务互相等待时,当一个等待时设置的某一阈值时,其中一个事物回滚,另一个等待的事务就能继续进行。用innodb_lock_wait_timeout来设置超时时间。超时机制FIFO不公平。(如果超时的事务所占的权重比较大,如事务操作更新了很多行,占用了较多的undo log)

33 死锁检测较常用的方法是wait-for-graph(等待图),采用深度优先的算法实现的

要求数据库中有以下两种信息:

锁的信息链表

事务等待链表

34 死锁的概率 事务的死锁发生的概率是非常低的,同时,事务发生死锁的概率与以下几点因素有关

系统中事务的数量,数量越多发生死锁的概率越大

每个事务操作的数量,每个事务操作的数量越多,发生死锁的概率越大

操作数据的集合,越小则死锁的发生死锁的概率越大

35 InnoDB存储引擎并不会回滚大部分的错误异常,但是死锁除外

36 InnoDB存储引擎不存在锁升级问题,因为不是根据每个记录来产生行锁的,相反,其根据每个事务访问的每个页对锁进行管理的,采用的是位图的方式,因此不管一个事务锁住页中一个记录还是多个记录,其开销通常都是一致的

你可能感兴趣的:(锁机制《mysql技术内幕InnoDB存储引擎》第六章锁机制笔记)