Mysql锁共享锁排它锁 (1)—mysql进阶(六十八)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: Mysql锁共享锁排它锁 (1)—mysql进阶(六十八)

前面说了为了解决脏读,幻读,不可重复读,mysql设置了四种隔离级别,read committed和read uncommitted会发生幻读和不可重复读,repeatable read会发生不可重复读,seriliztable,mysql默认是repeatable read,用mvcc解决不可重复读。设置隔离级别set global|session transaction isolation level …。当global时候,代表执行完之后其他所有session都可以使用当前设置的事务,如果是session则代表之后当前session才可以执行当前设置的事务,如果什么都没加,则是默认下一条事务提交完毕,就恢复之前的事务。Mvcc用他的readView链表控制解决这不可重复读,每次执行修改,都会吧修改的数据放入readView链表,链表有一个参数是trx_id,链表的头部第一条数据显示的是页面数据,后面的都是undo数据。里面有m_ids,min_trx_id,max_trx_id,creator_trx_id,主要在里面遍历,判断是否满足数据在当前事务可见性,比如creator_trx_id等于当前事务id,意味着该版本可以在当前事务查看,如果当前事务id大于mix_trx_id,表明该版本链在事务后才生成,则不可见,如果当前事务id小于min_trx_id,则表示该版链已提交,可以见。如果在这两个之间,则看是否事务id在m_ids里面,是就代表是活跃事务,不可见。这就保证了事务的可重复读。

事务隔离级别与MVCC (1)—mysql进阶(六十七)


解决并发事务带来问题的两种基本方式


前面说了事务并发可能带来各种问题,并发事务访问相同记录大致分为3种:

  1. 读-读 的情况:并发事务相继读取相同记录

因为读取并不会改变记录,所以并不会引起问题。

  1. 写-写 的情况:并发事务相继对相同的记录做出改动

我们前面说过这种情况就是脏写,脏写是在mysql四种隔离级别情况下都是不允许发生的。那么怎么解决脏写的呢,于是在多个事务并发写同一条数据的时候,让他们排队,这个排队的过程就是通过锁来实现的。这个锁其实是内存结构,一开始并没有锁和记录相关联。


当一个事务准备改动事务里的记录时,首先看看他有没有锁结构,当没有的时候吗,会在内存中生成一个锁结构。比方说t1要对这个记录做修改,要生成一个锁结构与之关联:

比方说修改t1里的数据,trx信息是t1,is_waiting:false。

锁结构两个重要的属性,一个就是trx信息,一个就是is_waiting。

一个代表是哪个事务的锁结构,一个代表当前事务是否在等待。

当t1需改这个数据,就生成了一个锁结构,因为他可以直接修改不需要等待,所以锁结构里的is_waiting是false。

这时候t2需要修改这个数据,因为检测到其他事务正在修改这个数据,所以这时候t2需要等待,他的is_waiting就是true。

当t1吧数据修改完毕,吧锁释放之后,会查看其他事务是否在等待,于是就把t2的is_waiting改为false,唤醒当前锁,让他执行。


综上:

不加锁:意思不需要在内存加锁结构,可以直接执行。

获取锁成功,加锁成功:意思是内存中生成了对应锁结构,而锁结构是false,表示可以执行。

获取锁失败,加锁失败:意思是内存中已经存在对应的锁结构,需要等待其他事务提交,当前事务才可以继续执行,表示true,需要等待执行。


读-写,写-读 的情况:也就是一个事务读,一个事务改动。

这种情况下可能出现脏读,幻读,不可重复读等问题。


Mysql在repeatable read已经解决了幻读问题,那么他是怎么解决脏读,幻读,不可重复读的问题呢?其实本质就是解决事务并发执行的问题,解决方案有两种:


方案一:读操作利用多版本并发控制,mvcc,写操作进行加锁

前面说过mvcc会生成一个版本链readView,由修改的数据和页面真实数据组成,readView第一条数据就是页面存在的数据,后面的数据就是undo 修改的数据。因为里面有creator_trx_id和min_trx_id,max_trx_id,m_ids,当前事务d与creator_trx_id相同,则可见,若大于max_trx_id,readView刚生成,不可见,若小于min_trx_id,则表示已经提交,可见,若在这之间,则判断当前事务是否在m_ids里,存在则代表当前事务活跃,不可见。而写入数据则是采用加锁的方式,这样保证读写不冲突。Read commtted 和 repeatable read是不同的,前者是每次selct都会创建一个readView版本链,而后者只有第一次select才创建,之后都是复用之前的readView版本链,解决了不可重复度和幻读。


方案二:读、写操作都用加锁来完成

我们在有些业务需求下,不允许用读取旧的事务,必须每次去读取最新的记录,比如银行里的业务,需要把账户余额读取出来,再加上本次金额,咋写入数据库。在操作当前数据的 时候,不想让其他事务访问本次数据,直到这次事务结束。这样的操作就需要在读和写都加锁。

(注意:读,写都加锁的话可以解决脏读,因为脏读是读取了另一个事务未提交的一条事务,如果给这个记录加了锁,那么就不可以读。不可重复读也可以解决,不可重复读是在事务里,两次读取的同一条值不同,这时候加锁了,就不会出现。但是解决幻读有点麻烦,幻读是因为读取了更多的数据,并不知道给那个多的数据怎么上锁,后面会介绍)


很显然,采用mvcc读写性能更高,一般情况下都是采用mvcc。但如果在特殊的业务场景下,会采用加锁的方式来解决业务问题。


一致性读(Consistent reads)


事务利用mvcc进行的读取操作称为一致性读,或者 一致性无锁读,有的地方称为 快照读。所有select语句在read committed 、 repeatable read隔离级别下都算一致性读。如:

Select * from t.
Select * from t left join t2.

一致性读并不会加锁,其他事务可以任意对表中的记录做自由修改。


锁定读(locking read)


共享锁和独占锁


前面说过并发的情况下 读-读 不会有问题,不过对于 写-写,读-写,写-读这些情况可能引引起一些问题,需要使用mvcc或者加锁的方式来解决。在使用加锁的方式解决问题时候,mysql设计了两个锁的分类:

共享锁:shared locks,简称s锁。事务读取一条记录时候,必须先获取该记录的锁。Lock in share mode 开启后另一个事务只可以读不可以修改。

独占锁:也叫排它锁,Exclusive locks,简称x锁。事务改动一条记录时候,先要获取这个锁。For update 开启后另一个事务不可以读也不可以修改。


写操作

平常用的写操作无非就是delete,insert,update这三种:


Delete:

对一条记录做delete操作,无非就是在b+树中定位到这条记录的位子,然后获取这条记录的排它锁,然后在执行delete mark操作。我们也可以吧这个定位待删除记录在b+树中位子过程看成是一个获取排它锁的锁定读。


Update:

如果对一条记录修改操作时候分为三种情况:

如果未修改这个主键值,并且存储空间没有发生变化,则直接就地修改,在b+树定位这条记录的位子,然后在获取这个记录的排他锁,最后在原记录的位子就行修改操作。其实也可以吧这个定位修改记录在b+树中位子过程看做是一个获取x锁的锁定读。

如果未修改这个记录的主键值,但存储空间发生了变化,则会先定位b+树的位子,获取排它锁,把这条记录放入垃圾链表,然后插入一条新的数据。定位修改记录的b+树位子可以看做排它锁的锁定读,insert操作提供隐式锁进行保护。

如果修改了该记录的主键,相当于在原纪录的基础上,先delete,在insert,加锁只需要按照delete和insert的规则就好。

Insert:

一般来说,新插入的数据不需要加锁,mysql提供一种隐式锁来保护这条新数据在事务提交之前,不被其他事物来访问。


多粒度锁


我们前面提到的锁针对的记录,可以说是行级锁,或者行锁,对一条记录加锁影响也只是这条记录而已,可以理解这个锁的颗粒度比较细。其实一个事务也可以在表级别进行加锁,自然称为表级锁或者表锁,对表加锁我们可以说这个锁的颗粒度比较粗,给表加锁分为共享锁和排它锁:


1、给表加s锁:

如果一个事务给表加s锁,那么,

别的事务可以继续获得该表的s锁。

别的事务可以继续获取该表某些记录的s锁。

别的事务不可以获取该表的排它锁。

别的事务不可以获取该表一些记录的排它锁。


2、给表加排它锁:

如果一个事务给表加排它锁(意味着独占这个表),那么:

别的事务不可以继续获得该表的s锁。

别的事务不可以继续获取该表某些记录的s锁。

别的事务不可以获取该表的排它锁。

别的事务不可以获取该表一些记录的排它锁。


我们在实际生活中举个例子:


教室一般是公用的,当有学生进入的时候,会在门口加个s锁,这时候如果很多学生进去,则很多s锁。

如果有维修人员来修理天花板或者空调或者电路等,这时候就不能让学生进去,这时候上个x锁。


当有特殊需求:

当学校领导来参观的时候,给教室上个表级别的s锁,因为学生可以正常进入学习,但是维修人员不可以进入,要等s锁解除,才会上个x锁。


当学校占用教学楼考试:

此时会给教室上个x锁,维修人员和学生都不可以进入,类似表级别的x锁。


但这里面有两个问题:

如果想对整栋楼上s锁,首先确保楼里没有正在维修的教室,否则要等他维修完毕才上s锁。

如果想对整栋楼上x锁,首先需要确保没有考试的教室和维修的教室,如果有的话,需要等他们全部锁释放,才可以整栋楼上x锁。

这时候我们怎么知道整栋楼里有没有教室上锁呢,难道一次遍历,那太慢了,于是innoDB有个意向锁,Intention locks:

意向共享锁:intention shared locks,is锁,当事务给某行记录上s锁的时候,还会上个is锁。

意向排它锁:intention exclusive locks,ix锁,当事务给某行记录上行x锁的时候,还会上个ix锁。

所以不需要遍历,只需要在表锁的时候判断一下is和ix是否锁了就行。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
2月前
|
SQL 关系型数据库 MySQL
MySQL 锁
MySQL里常见的几种锁
54 3
|
2月前
|
SQL 关系型数据库 MySQL
案例剖析,MySQL共享锁引发的死锁问题!
案例剖析,MySQL共享锁引发的死锁问题!
|
2月前
|
存储 关系型数据库 MySQL
优化 MySQL 的锁机制以提高并发性能
【10月更文挑战第16天】优化 MySQL 锁机制需要综合考虑多个因素,根据具体的应用场景和需求进行针对性的调整。通过不断地优化和改进,可以提高数据库的并发性能,提升系统的整体效率。
91 1
|
2月前
|
关系型数据库 MySQL Java
MySQL数据锁:Record Lock,Gap Lock 和 Next-Key Lock
本文基于 MySQL 8.0.30 版本及 InnoDB 引擎,深入解析三种行锁机制:记录锁(Record Lock)、间隙锁(Gap Lock)和临键锁(Next-key Lock)。记录锁锁定索引记录,确保事务唯一修改;间隙锁锁定索引间的间隙,防止新记录插入;临键锁结合两者,锁定范围并记录自身,有效避免幻读现象。通过具体示例展示了不同锁的作用机制及其在并发控制中的应用。
179 2
|
2月前
|
存储 关系型数据库 MySQL
MySQL数据库锁:共享锁和独占锁
本文详细介绍了`InnoDB`存储引擎中的两种行级别锁:共享锁(S锁)与排他锁(X锁)。通过具体示例展示了这两种锁的工作机制及其在`InnoDB`与`MyISAM`引擎中的表现差异。文章还提供了锁的兼容性矩阵,帮助读者更好地理解锁之间的互斥关系。最后总结了两种锁的特点及适用场景。适合希望深入了解`MySQL`并发控制机制的读者阅读。
70 1
|
3月前
|
监控 关系型数据库 MySQL
MySQL锁机制与解决死锁问题
MySQL锁机制与解决死锁问题
319 5
|
2月前
|
存储 关系型数据库 MySQL
MySQL锁,锁的到底是什么?
【10月更文挑战第16天】MySQL 锁锁定的是与数据和资源相关的对象,其目的是为了保证数据的一致性、避免冲突,并在并发环境下合理协调事务或操作的执行。理解锁的对象和意义对于优化数据库性能、处理并发问题至关重要。
72 0
|
2月前
|
关系型数据库 MySQL 数据库
mysql锁详解
通过理解并合理运用MySQL中的锁机制,开发者可以有效管理数据库并发访问,平衡性能与数据一致性需求。更多关于MySQL锁的深入探讨和最佳实践,请参考专业的数据库管理资源[[深入MySQL锁机制详解
43 0
|
3月前
|
存储 SQL 关系型数据库
MySQL 的锁机制,那么多的锁,该怎么区分?
MySQL 的锁机制,那么多的锁,该怎么区分?
46 0
|
3天前
|
SQL 关系型数据库 MySQL
MySQL导入.sql文件后数据库乱码问题
本文分析了导入.sql文件后数据库备注出现乱码的原因,包括字符集不匹配、备注内容编码问题及MySQL版本或配置问题,并提供了详细的解决步骤,如检查和统一字符集设置、修改客户端连接方式、检查MySQL配置等,确保导入过程顺利。