MySQL技术内幕InnoDB存储引擎阅读相关笔记-锁

一、InnoDB锁

对于MyISAM引擎来说,其锁是表锁。InnoDB引擎提供行锁。

1、InnoDB行锁

1)、共享锁(S Lock),允许事务读一行数据。

​ 2)、排他锁(X Lock),允许事务删除或者更新一行数据。

​ 当一个事务已经获得了行R的共享锁,其他事务可以立即获得该行R的共享锁,我们称之为锁兼容。但如果有事务像获得行R的排他锁,则它必须等待事务释放行上的共享锁,我们称之为锁不兼容。

XS
X冲突冲突
S冲突兼容

​ 下面我们来看一个例子:

在这里插入图片描述

在这里插入图片描述

​ 可以看到我们在一个会话A使用了S锁,所以另一个B会话就不会获取到X锁了。不过我们来看下查询另一个Id:

在这里插入图片描述

​ 可以看到我们并没有提交前面A会话的事务,B会话能给另一个Id加X锁。通过这个验证即表明了是使用的行锁,同时也表明了X锁与S锁是不兼容的。

​ 3)、意向锁

​ InnoDB存储引擎支持多你读的锁定,即允许行级锁与表级锁同时存在。为了支持这种不同粒度的加锁操作,InnoDB存储引擎支持一种额外的锁方式,即意向锁。意向书是表级锁,其的目的主要是为了在一个事务中揭示下一行将被请求的锁类型,其不需要你主动操作。可以简单的将其理解,其表明这张表目前的加X或者S锁的状态。

​ 意向共享锁(IS Lock):事务想要获得一个表中某几行的共享锁

​ 意向排他锁(IX Lock):事务想要获得一个表中某几行的排他锁

2、锁&事务状态查看

1)、查看事务的锁状态

在这里插入图片描述

​ 这里我们另起一个C会话,使用show engine innodb status\G查看,可以看到这里锁的行数是1。所以也就是说,S锁是不在这个行级锁统计的。

2)、schema.INNODB_TRX表查看

在这里插入图片描述

​ 参数意义:

​ trx_id:事务id,可以看到其与上面事务那个ID是对应的

​ trx_state:当前事务的状态

​ trx_started:事务开始的时间

​ trx_request_lock_id:等待事务的锁ID。如果trx_state的状态是LOCK_WART,则该值代表当前事务等待之前事务占用锁资源的ID。我们以最开始B会话超时那条语句来看下

在这里插入图片描述

​ trx_wait_started:事务等待开始的时间

​ trx_weigth:事务的权重,反映一个事务修改和锁住的行数。在InnoDB存储引擎中,当发生死锁需要回滚时,InnoDB存储引擎会选择该值最小的进行回滚。

​ trx_mysql_thread_id:Mysql中的线程ID,SHOW PROCESSLIST显示结果

在这里插入图片描述

​ trx_query:事务有限的sql

3)、information_schema.INNODB_LOCKS查看锁状态

在这里插入图片描述

​ 参数说明:

​ lock_id:锁的ID

​ lock_trx_id:事务ID

​ lock_mode:锁的模式

​ lock_type:锁的类型,锁的类型,表锁还是行锁

​ lock_table:要加锁的表

​ lock_index:锁的索引

​ lock_space:InnoDB存储引擎表空间的ID号

​ lock_page:被锁住的页的数量。表锁的话,该值为NULL

​ lock_rec:被锁住行的数量,表锁为NULL

​ lock_data:被锁住行的主键值,表锁为NULL

4)、information_schema.INNODB_LOCK_WAITS表查看锁冲突信息

在这里插入图片描述

​ 参数说明:

​ requesting_trx_id:申请获取锁资源的事务ID

​ requesting_lock_id:申请获取锁资源的ID

​ blocking_trx_id:阻塞的事务ID(现在资源的占有者)

​ blocking_trx_id:阻塞的锁ID

二、一致性的非锁定读操作

1、介绍基本内容

​ 一致性的非锁定行读(consistent nonlocking read)是指InnoDB存储引擎通过行多版本控制(multi versioning)的方式来读取当前执行时间数据库行的数据。例如会话A在读取的时候,这个时候有其它的会话B等在进行delete、update操作,A并不会等B这些释放锁,而是直接去读取快照数据。

在这里插入图片描述

2、多版本并发控制

​ 上面就是非锁定读,其会大大提高数据读取的并发性。在InnoDB的默认设置情况下,这是默认的读取方式,即读取并不会占用和等待表上的锁。但在不同的事务隔离级别下,读取的方式并不相同,并不是每个事务隔离级别下读取的都是一致性读。同样,即使都是一致性读,但第一快照数据的定义也不相同。

​ 快照数据就是当前行数据之前的历史版本,可能有多个版本,我们称这种技术为行多版本技术。这种并发控制,就是多版本并发控制(Multi Version Concurrency Controller,MVCC)

​ 在Read CommittedRepeatable Read(InnoDB默认隔离级别)下,InnoDB使用非锁定的一致性读,但这两种对于快照数据的定义不同。

Read Committed:对于快照数据,非一致性读总是读取被锁定行的最新一份的快照数据。由于是最新的一份,所以也就可能出现不可重复读

Repeatable Read:其对于快照数据的读取,总是读取事务开始时的行数据版本。这样就解决了不可重复读的问题。不过又会出现幻读,因为上面是行级别的控制,幻读是表级别的。所以要解决这个问题就需要串行处理。

​ 在这里上面有举一个SQL案例来说明读已提交、可重复读,这个网上现在已经有很多例子了,这里就不再写了。上面梳理的行的多版本并发控制就解释了这两种级别的具体操作。

三、锁的算法

1、基本内容

​ InnoDB存储引擎有3种行锁的算法设计:

Record Lock:单个行记录上的锁

Gap Lock:间隙锁,锁定一个范围,当不包含记录本身

Next-key LockGap lock+Record Lock,即行锁+间隙锁。其锁定一个范围,并且锁定记录本身。

​ 1)、Record Lock总是去锁住索引记录。如果InnoDB表建立的时候并没有设置任何索引,其就会使用InnoDB默认的隐式主键来锁定。

​ 2)、Next-key Lock是结合Gap LockRecord Lock的一种锁定算法,在Next-key Lock算法下,InnoDB对行的查询都是使用这种锁定算法。对应不同的SQL查询语句,可能设置共享的Next-key Lock或排他的Next-key Lock

2、案例说明

在这里插入图片描述

在这里插入图片描述

​ 通过上面这两个会话A、B,我们可以看到已经验证了Next-key Lock的锁住范围(id = 5)、锁住当前行(id = 6)。这里再id = 5 | 6的时候语句是阻塞的,我直接切断了。

​ 同时还需要注意的是,上面是范围id < 6,如果是直接id = 6,则其就会使用间隙锁而是直接行锁Record Lock

四、一些名词介绍(锁问题)

1、脏数据

脏数据是指当前事务读到了其他事务还没有提交的数据,由于数据A还没有提交,其是这个数据A并不是确认的,可能发生回滚,也就并没有生效,这个会发生在READ UNCOMMITTED读未提交事务隔离级别。

2、脏页

​ 脏页是指缓冲池中已经被修改的页,但整个时候还并有刷新写到磁盘(写磁盘是异步的,也就是说目前这个数据只是存在再内存中),所以这个时候磁盘中的页数据与缓存中的页数据并不一致。脏页并没有问题。

3、不可重复读

​ 就是前面介绍到在多版本并发控制其会读取最新版本的行数据。例如事务A先开启一个事务查询到一行数据,然后处理其他的内容(还并没有提交事务),这个时候事务B只有一条修改一样行的语句就直接提交了。这个时候由于读取最新版本的原因,当事务A再次读取的时候就与第一次不同了。这里书上也有一个例子说明,也可以去搜索其他博文具体了解。

4、死锁

1)、基本介绍

​ 如果程序是串行的,则并不会发生死锁。死锁只发送于并发的情况。

​2)、demo

在这里插入图片描述

在这里插入图片描述

​ 这里的两个会话,顺序是交叉的,先是A会话id = 5 for update,再B会话id = 6 for update。然后在A会话id = 6 for update的时候会阻塞(图片这里并没有体现出来),然后在B会话id = 5 for update的时候就会给出Deadlock,然后A会话就查询出来了。

​ 上面就是演示两个会话分别给对方需要的资源上锁了,然后两个都不能获取到想要的资源就发生了死锁了。同时通过上面的可以判断,发生死锁,Mysql默认会释放掉锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值