详解MySQL的并发控制

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 1.概述所谓的并发控制,就是规避多个会话并发访问数据库带来的诸如脏数据之类的数据一致性问题,MySQL中提供了一系列的机制让我们可以去进行并发控制。本质上来说MySQL就是用的两种锁来进行并发控制,一种是表锁,锁住整张表;一种是行锁,锁住某个数据行。

1.概述

所谓的并发控制,就是规避多个会话并发访问数据库带来的诸如脏数据之类的数据一致性问题,MySQL中提供了一系列的机制让我们可以去进行并发控制。

本质上来说MySQL就是用的两种锁来进行并发控制,一种是表锁,锁住整张表;一种是行锁,锁住某个数据行。

平时我们使用的时候,很少会直接去操作锁,因为MySQL已经帮我们封装的很好了,直接用innodb引擎+事务就能很好的进行并发控制,事务底层其实依赖的就是行锁。


本文会先聊事务、再聊表锁、行锁,但其实总的来说MySQL进行并发控制,就是行锁和表锁,事务的底层用的就是行锁,只是事务太重要了所以单独拎出来作为一个独立的章节聊。

2.事务

2.1.什么是事务

注意:只有innodb引擎是支持事务的,所以本文与事务相关的讨论,默认都是在innodb引擎下。

在实际使用中,会存在这样一类场景,我们希望几条SQL要么同时执行成功,要么同时失败,不能有的成功,有的失败。


比如网购下单,生成订单、扣减库存两条SQL,必须保证要么全部成功,要么全部失败,不能说生成订单成功,但是扣减库存失败了,或者说扣减库存成功但是生成订单失败了,以上任何一种情况都是会产生脏数据的。如果两者中有一者失败,另外一个也需要跟着执行不成功,从而保证数据的正确性。


事务就是为了满足将多条捆绑在一起,同成功,同失败而出现的。人们在实现事务过程中,发现事务要实现上面我们说的效果,那么就必须实现四点:


原子性(Atomicity)

一致性(Consistent)

隔离性(Isolation)

持久性(Durable)

也就是大名鼎鼎的ACID,很多地方称其为事务的四大特性。

1.原子性:


事务是一个原子操作单元,其对数据的修改,要么全部执行,要么全部不执行。


2.一致性:


数据库中的数据总是从一个状态到另一个状态,不能存在中间状态。继续以网购下单为例,一开始的数据库中的数据为A状态,执行完事务,扣减库存、新增订单后的数据状态为B状态,数据库只能由A到B,不能出现诸如扣了库存,没生成订单,或者生成了订单,没扣库存这样的中间状态。


3.隔离性:

一个事务在提交之前,其所做的修改对其它事务来说是不可见的。不保证隔离性会产生脏数据,这个很好理解,举个例子:


A的银行账户有400,有两个事务,彼此之间数据可见,也就是一个事务修改数据,不管提没提交其他事务都看得见。


事务1,A向B转200:


A的账户扣减200

B的账户新增200

事务2,A向C转200:


A的账户扣减200

C的账户新增200

如果在事务1中的1、2步的时间间隙内事务2间插执行完毕,那么在事务1第2步执行前A的账户中已经被扣减了两次200,余额为0,C的账户中多了200。


这时候如果在事务1的第2步中出错了、回滚,那么A的账户又会回到事务1第一步执行之前的状态,也就是A的账户又恢复成了400。最后C的账户平白无故多了200。

4.持久性:

事务完成后,其对数据的修改是永久的,即使系统断电、重启,也不会变。

2.2.事务的隔离级别

2.2.1.三种数据一致性问题

在没有隔离性的情况下,事物之间会出现3种数据一致性问题:


脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。

幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。

2.2.2.四种隔离级别

隔离级别可理解为,隔离性的严格度,MySQL并不是固定死了各个事务间就是不可读的,而是规定了各种强度的隔离级别。


观察上面3种数据一致性问题就会发现,解决它们需要的隔离性是递增的,MySQL一共给出4种隔离级别,隔离性也是递增的,对应解决以上3个问题,有3种,加上1种3种问题都能覆盖解决的:


Read Uncommitted(读未提交):最低的隔离级别,允许一个事务读取另一个事务尚未提交的数据变更。可能导致脏读(Dirty Read)问题。


Read Committed(读已提交):确保一个事务只能读取另一个事务已经提交的数据变更。防止脏读问题,但可能导致不可重复读(Non-repeatable Read)问题。


Repeatable Read(可重复读):确保在同一个事务中多次读取同一数据时,能够得到一致的结果。防止脏读和不可重复读问题,但可能导致幻读(Phantom Read)问题。


Serializable(串行化):最高的隔离级别,强制事务串行执行,确保不会发生脏读、不可重复读和幻读问题。但是并发性能较差,通常不建议在高并发环境中使用。

2.3.如何设置隔离级别

可以在连接字符串中设置隔离级别:

jdbc:mysql://localhost/mydatabase?useSSL=false&characterEncoding=utf8&transactionIsolation=隔离级别

可以通过SQL在会话中设置隔离级别:

 ACTION ISOLATION LEVEL 隔离级别;
SET TRAN

3.锁

3.1.锁与事务的关系

锁是计算机协调多个进程或线程并发访问某一资源的机制,用来解决并发访问带来的数据一致性问题。在数据库中,除传统的计算资源(如CPU、IO、RAM)的争用以外,数据更是会被并发访问的资源。所以MySQL数据库也用锁机制来保证数据并发访问的一致性。


不同的隔离级别底层就是用不同的锁来实现的。

3.2.分类

MySQL的锁可以从两种维度来分,

一个维度是按照锁的是一行,还是锁的是整张表,分为:

  • 行锁
  • 表锁

另一个维度是按照锁的操作是读操作,还是写操作,分为:

  • 读锁
  • 写锁

3.3.表锁

3.3.1.概述

MySQL中innodb引擎和myisam引擎均支持用lock tables指令来锁表。

3.3.2.读锁

读锁,一种共享锁,针对被锁表,所有会话都可以进行读操作,所有会话都无法进行写操作。加锁方和其他客户端的区别是,加锁方直接不允许进行写操作,而其他会话的写操作允许进行,只是会被阻塞挂起。锁解开后,所有挂起的操作线程会去重新争抢资源。

加锁指令:

lock tables 表名 read;

释放锁指令:

unlock tanles;

加锁方不允许进行写操作:

a997fc8b371d4b22b99ac35730f9bcd9.png

其它客户端的写操作在加锁方释放锁之前都被挂起:

3.3.3.写锁

写锁,排它锁,针对被锁表,加锁方可以读写,其他会话的写操作会直接失败,读操作会被阻塞挂起,解锁以后,被挂起的线程会重新去争抢资源。

加锁指令:

lock tables 表名 write;

其它会话的读操作、写操作在加锁方释放锁之前都被阻塞挂起:

43991efaab7d45f893c6ac824e19268f.png

image.png

3.3.4.保护机制

读锁、写锁中,加锁方都只能读当前被自己锁定的表,这是MySQL的一个保护机制,为的就是强制要求加锁方给出一个说法,到底准备锁多久,不给说法不让走。

a15b9b63800b4db18cab0275b3132d54.png

3.4.行锁

3.4.1.概述

innodb和myIsam最大的不同有两点,一是支持事务,二是支持行级锁。

3.4.2.什么是MVCC

行锁没有显式的声明办法,而是藏在默认实现中,MVCC 是 MySQL InnoDB 存储引擎的默认并发控制机制,其采用的就是表锁。


并发控制有几种处理方法,


第一种: 基于锁的并发控制,程序员B开始修改数据时,给这些数据加上锁,程序员A这时再读,就发现读取不了,处于等待情况,只能等B操作完才能读数据,这保证A不会读到一个不一致的数据,但是这个会影响程序的运行效率。


第二种:MVCC,每个用户连接数据库时,看到的都是某一特定时刻的数据库快照,在B的事务没有提交之前,A始终读到的是某一特定时刻的数据库快照,不会读到B事务中的数据修改情况,直到B事务提交,才会读取B的修改内容。


MVCC其实就是实现事务的关键,后续会有文章专门深入聊事务的实现,此处暂不展开。


3.4.3.mvcc的使用

首先有一个需要纠正的是,很多地方都说mvcc是通过手动提交来触发的,这是个误导,不管手动提交还是自动提交MVCC机制都是生效的,只是手动提交用来观察mvcc过程更加直观。


此处为了直观,我们也以手动提交为例,首先通过set  autocommit=0可以关闭自动提交。关闭后每次执行sql以后,通过commit命令来手动提交,才会对数据库产生影响,否则只会对当前操作方的数据快照有影响。innodb引擎中,其他客户端想查看到最新的数据情况也必须通过commit指令来做一次同步(因为innodb默认隔离级别为可重复读)。


当一个会话修改某行数据,未commit前,其他会话对该行数据的修改会阻塞挂起,直到先改那个会话commit为止。

image.png

3.4.4.间隙锁

使用范围条件匹配时,innodb会给符合条件的已有数据记录的索引加“范围锁”(范围锁是特殊的行锁),对于键值在条件范围内但并不存在的记录,叫做间隙(GAP),innodb也会对这个间隙加锁,这种机制叫做“间隙锁”。

53465b5c2f394547a41d986c8eaa1885.png

3.4.5.行锁变表锁

任何需要全表扫描的情况时,行锁都会升级为表锁。

因为MySQL不知道到底该锁哪行,所以会将整个表都锁起来,然后再进行全表扫描。

全表扫描的情况无非两种:

  1. 没建索引。
  2. 索引失效。

4818b452059d43549b4f0b8d0804c565.png

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
打赏
0
1
0
0
22
分享
相关文章
MySQL MVCC全面解读:掌握并发控制的核心机制
【10月更文挑战第15天】 在数据库管理系统中,MySQL的InnoDB存储引擎采用了一种称为MVCC(Multi-Version Concurrency Control,多版本并发控制)的技术来处理事务的并发访问。MVCC不仅提高了数据库的并发性能,还保证了事务的隔离性。本文将深入探讨MySQL中的MVCC机制,为你在面试中遇到的相关问题提供全面的解答。
535 2
MySQL并发支撑底层Buffer Pool机制详解
【10月更文挑战第18天】在数据库系统中,磁盘IO操作是性能瓶颈之一。为了提高数据访问速度,减少磁盘IO,MySQL引入了缓存机制。其中,Buffer Pool是InnoDB存储引擎中用于缓存磁盘上的数据页和索引页的内存区域。通过缓存频繁访问的数据和索引,Buffer Pool能够显著提高数据库的读写性能。
349 2
案例剖析:MySQL唯一索引并发插入导致死锁!
案例剖析:MySQL唯一索引并发插入导致死锁!
484 0
案例剖析:MySQL唯一索引并发插入导致死锁!
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
事务是MySQL中一组不可分割的操作集合,确保所有操作要么全部成功,要么全部失败。本文利用SQL演示并总结了事务操作、事务四大特性、并发事务问题、事务隔离级别。
1325 2
【MySQL基础篇】事务(事务操作、事务四大特性、并发事务问题、事务隔离级别)
Mysql并发控制和日志
通过深入理解和应用 MySQL 的并发控制和日志管理技术,您可以显著提升数据库系统的效率和稳定性。
237 10
MySQL MVCC深度解析:掌握并发控制的艺术
【10月更文挑战第23天】 在数据库领域,MVCC(Multi-Version Concurrency Control,多版本并发控制)是一种重要的并发控制机制,它允许多个事务并发执行而不产生冲突。MySQL作为广泛使用的数据库系统,其InnoDB存储引擎就采用了MVCC来处理事务。本文将深入探讨MySQL中的MVCC机制,帮助你在面试中自信应对相关问题。
292 3
优化 MySQL 的锁机制以提高并发性能
【10月更文挑战第16天】优化 MySQL 锁机制需要综合考虑多个因素,根据具体的应用场景和需求进行针对性的调整。通过不断地优化和改进,可以提高数据库的并发性能,提升系统的整体效率。
383 1
做MySQL 的并发控制
本文以 MySQL 8.0.35 的代码为例,尝试对 MySQL 中的并发访问控制进行一个整体的介绍。
MySQL高级篇——MVCC多版本并发控制
什么是MVCC、快照读与当前读、隐藏字段、Undo Log版本链、ReadView、举例说明、InnoDB 解决幻读问题
MySQL实现并发控制的过程
数据库系统到底是怎么进行并发访问控制的?本文以 MySQL 8.0.35 代码为例,尝试对 MySQL 中的并发访问控制进行整体介绍。