MySQL事务和锁机制

MySQL技术——事务和锁机制

    • 一、事务
      • (1)概述
      • (2)ACID特性
      • (3)事务并发存在的问题
      • (4)事务的隔离级别
    • 二、锁机制
      • (1)锁的力度
      • (2)表的分类: 排他锁、共享锁
      • (3)串行化解决幻读(虚读)问题 :间隙锁
      • (4)意向共享锁和意向排他锁
      • (5)死锁
      • (6)锁的优化建议
    • 三、多版本并发控制(MVCC)
    • 四、MySQL优化问题
    • 五、总结

一、事务

(1)概述

事务是数据库区别于文件系统的重要特征之一。在文件系统中,如果正在写文件,但是操作系统奔溃了,这个文件就很有可能被破坏。当然,有一些机制可以把文件回复到某个时间点。不过,如果需要保证两个文件同步,这些文件系统可能就显得无能为力了,例如,当需要更新两个文件时,更新完一个文件后,在更新完第二个文件之前系统重启了,就会产生两个不同步的文件,因此这也就是数据库系统引入事务的主要目的

一个事务是由一条或者多条数据库操作SQL语句所组成的一个不可分割的单元,只有当事务中的所有操作都正常执行完毕后,整个事务才会被提交给数据库;如果由部分事务处理失败,那么事务就要回退到最初的状态。因此事务要么全部执行成功,要么全部失败

(2)ACID特性

每一个事务都必须满足下面的4个特性:

  • 事务的原子性(Atomic): 事务是一个不可分割的整体,事务必须具有原子特性,要么全执行,要么全不执行
  • 事务的一致性(Consistency): 一个事务执行之前和执行之后,数据库数据必须保持一致性状态。数据库的一致性状态必须由用户来负责,由并发控制机制实现
  • 事务的隔离性(Isolation): 当两个或者多个事务并发执行时,为了保证数据的安全性,将一个事务内部的操作与其他事务的存在隔离起来,不被其他正在执行的事务看到,使得并发执行的各个事务之间不能相互影响 | 锁 + MVCC
  • 事务的持久性(Durability): 事务完成(commit)后,DBMS保证它对数据库中的数据是永久性的,即使数据库因为故障出错,也应该能够快速恢复数据

(3)事务并发存在的问题

如果事务处理不经过隔离,并发执行事务是通常会发生以下问题:

  • 脏读(Dirty Read): 一个事务读取了另一个事务为提交的数据,例如当事务A和事务B并发执行时,当事务A更新后,事务B查询读取到事务A尚未提交的数据,此时事务A回滚,则事务B读到的数据就是无效的脏读数据(事务B读取到来事务A未提交的数据
  • 不可重复读(NonRepeatable Read): 一个事务的操作导致另一个事务前后两处读取到不同的数据。即当事务A和事务B并发执行时,当事务B查询读取到数据后,事务A更新操作更改事务B查询到的数据,此时事务B再次去读取该数据,发现前后两处读的数据不一样(事务B读取了事务A已经提交的数据
  • 虚读 / 幻读(Phantom Read): 一个事务的操作导致另一个事务前后两次查询的结果 数据量不同 ,即当事务A和事务B并发执行时,当事务B查询读取数据后,事务A新增或者删除了一条满足事务B查询条件的记录,此时事务B再去查询,发现查询到前一次不存在的记录,或者前一次查询的一些记录不见了(事务B读取了事务A新增的数据,或者读不到事务A删除的数据

(4)事务的隔离级别

MySQL默认支持四种隔离级别,如下图:

隔离级别脏读不可重复读虚读 / 幻读
未提交读:TRANSACTION_READ_UNCOMMITTED可以可以可以
已提交读:TRANSACTION_READ_COMMITTED不可以可以可以
可重复读:TRANSACTION_REPEATABLE_READ不可以不可以update 可以
串行化: TRANSACTION_SERIALIZABLE不可以不可以不可以
  • 串行化是最高的事务级别,由于事务隔离级别越高,为避免冲特所花费的性能也越多
  • 在“可重复读”级别中,实际上是可以解决部分的虚读问题,但是不能防止update更新产生的虚读问题,还是要串行化隔离级别

select @@transation_isolation; mysql默认的隔离级别:可重复读在这里插入图片描述

我们现在一一列举各种隔离级别会出现的结果

  • 未提交读 READ_UNCOMMITTED
    在这里插入图片描述

  • 已提交读 READ_COMMITTED
    在这里插入图片描述

  • 可重复读 REPEATABLE-READ,这里对于幻读就不演示了,可以自行验证
    在这里插入图片描述

  • 串行化 SERIALIZABLE
    在这里插入图片描述

二、锁机制

(1)锁的力度

锁的力度分为两种:

  • 表级锁:对整张表加锁,开销小,加锁块,不会出现死锁;锁的力度大,发送锁冲突的概率高,并发度低
  • 行级锁:对某行记录加锁。开销大,加锁慢,会出现死锁;锁定力度最小,发生锁冲突的概率最低,并发度高
    • InnoDB行锁是通过给索引上的索引项加锁来实现的,而不是给表的行记录加锁实现的,这就意味着只有通过索引条件检索数据,InnoDB才使用行级锁,否则InnoDB将使用表锁。
    • 由于InnoDB的行锁实现是针对索引字段添加的锁,不是针对行记录加的锁,因此虽然访问的是InnoDB引擎下表的不同行,但是如果使用相同的索引字段作为过滤条件,依然会发生锁冲突,只能串行进行,不能并发进行。
    • 即使SQL中使用了索引,但是经过MySQL的优化器后,如果认为全表扫描比使用索引效率更高,此时会放弃使用索引,因此也不会使用行锁,而是使用表锁,比如对一些很小的表,MySQL就不会去使用索引。

(2)表的分类: 排他锁、共享锁

  • 共享锁(Shared)
  • 排他锁(Exclusive):又称X锁,写锁
  • 共享锁(Shared):又称S锁,读锁

X和S锁之间由以下关系:SS可以兼容,SX、XX、XS之间是互斥的

  • 一个事务对数据对象O加了S锁,可以对O进行读取操作但不能进行更新操作。加锁期间其他事务能对O加S锁但不能加X锁
  • 一个事务对数据对象O加了X锁,就可以对O进行读取和更新。加锁期间其他事务不能对O加任何锁
显示加锁语句
select ... lock in share mode;  #强制获取共享锁
select ... for update;	   #获取排他锁

下面我们来演示一下,两种锁的效果

假设我们开启了两个事务,默认工作在隔离级别为可重复读,两个事务先后执行以下语句 select * from stu where id = 2 for update,根据上述推导,XX是不可兼容的,所以前一个执行sql语句的事务会对当前查询的记录加一把排他锁,后执行sql语句的事务肯定会被阻塞;若后执行sql语句的事务换成执行... lock in share mode,同样也是阻塞,因为XS也是不兼容的;若后执行的事务获取其他记录的锁,如id = 3 for update,该记录没有加X锁,因此可以执行
在这里插入图片描述
我们再来看看另外一条sql语句 select .. name = 'aaa' for update
在这里插入图片描述
select 'bbb'竟然也会阻塞!!!
这里注意:InnoDB的行锁是加在索引项上面的,并不是单纯的给行记录加锁;如果过滤条件没有索引的话,name只是普通字段,使用的就是表锁,而不是行锁!!!
这里如果我们给name字段添加索引的话,就是加行锁,使得’bbb’能够执行
在这里插入图片描述
我们来看看隔离级别为 SERIALIZABLE的结果
在这里插入图片描述

(3)串行化解决幻读(虚读)问题 :间隙锁

当我们用范围条件而不是等值条件去查询数据时,并请求共享或者排他锁时,InnoDB会给符合条件的已有数据记录的索引项加锁;对于键值在条件范围内但是并不存在的记录,叫做“间隙(GAP)”,InnoDB也会对这个“间隙”加锁,这种锁机制就是所谓的间隙锁。

目的:防止幻读,以满足川=串行化隔离级别的要求

锁的三张算法:

  • record lock:行锁
  • gap lock:间隙锁
  • next-key lock:record lock + gap lock

示例1 范围查询:按过滤条件分为:使用主键索引 或者 辅助索引
在这里插入图片描述
在这里插入图片描述


示例二 等值查询
在这里插入图片描述
在这里插入图片描述

(4)意向共享锁和意向排他锁

在使用表锁的时候,涉及到的效率问题
要获取一张表的S或者X锁,需要检查这张表没有被其他事务获取过X锁,这表里的数据没有被其他事务获取过行锁X锁,那么如果这张表有非常多的数据,是一行一行的检查???
意向共享锁和意向排他锁就是用来解决这个问题

  • 意向共享锁(IS锁): 事务计划给记录加行共享锁,事务在给一行记录加共享锁前,必须先取得该表的IS锁
  • 意向排他锁(IX锁): 事务计划给记录加行排他锁,事务在给一行记录加排他锁前,必须先取得该表的IX锁

当我们需要获取表的X锁时,不需要再检查表中的哪些行被(X或者S)锁占用,只需要检查IX和IS锁即可!

如下图的 X和S都是表锁

XIXSIS
XConflictConflictConflictConflict
IXConflict兼容Conflict兼容
SConflictConflict兼容兼容
ISConflict兼容兼容兼容

1、意向锁是由InnoDB存储引擎获取行锁之前自己获取的
2、意向锁之间都是兼容的,不会产生冲突
3、意向锁存在的意义是为了更高效的获取表锁
4、意向锁是表级锁,协调表锁和行锁的共存关系,主要目的是显示事务正在锁定某行或者试图锁定某行。

(5)死锁

MyISAM表锁是deadlock free的,这是因为MyISAM总是一次获得所需的所有锁,要么全部满足,要么等待,因此不会发生死锁。但在InnoDB中,出来的单个SQL组成的事务外,锁是逐步获得的,即锁的力度比较小,发生死锁也是可能的,如下:

在这里插入图片描述
在这里插入图片描述

死锁问题一般都是我们自己的应用造成的,和多线程编程的死锁情况相似,大部分都是由于我们多个线程在获取多个锁资源的时候,获取的顺序不同而导致的死锁问题。因此我们应用在对数据库的多个表做更新的时候,不同的代码段,应对这些表按相同的顺序进行更新操作,以防止锁冲突导致死锁问题。

(6)锁的优化建议

  1. 尽量使用较低的隔离级别
  2. 设计合理的所有并尽量使用索引访问数据,使锁更加准确,减少锁冲突的机会提高并发能力
  3. 选择合理的事务大小,小事务发生锁冲突概率小
  4. 不同的程序访问一组表时,应尽量约定以相同的顺序访问各表,对于一个表而言,尽可能以固定的顺序存取表中的行,这样也能减少死锁的发生
  5. 尽量用相等条件访问数据,这样可以避免间隙锁对并发插入的影响
  6. 不要申请超过实际需要的锁级别
  7. 除非必须,查询时不要显示加锁

三、多版本并发控制(MVCC)

MVCC(Multi-Version Concurrency Control,简称MVCC),是MySQL中基于乐观锁理论实现隔离级别的方式,用于已提交读可重复读隔离级别的实现,也经常被称为多版本并发控制。MVCC机制会生成一个数据请求时间点的一致性数据快照(Snapshot),并用这个快照来提供一定级别的一致性读取。从用户的角度来看,就是数据库提供同一组数据的多个版本(系统版本号和事务版本号)。

MVCC多版本控制的读操作分为两类:

  • 快照读:读的是记录的可见版本,不用加锁,如select
  • 当前读:读的是记录的最新版本,并且返回当前的记录,如insert,delete,select,update,select … lock in share mode / for update

MVCC: 每一行记录实际上有多个版本,每个版本的记录除了数据本身之外,增加了其它字段

  • DB_TRX_ID:记录当前事务ID
  • DB_ROLL_PTR:指向undo log日志上数据的指针

已提交读: 每次执行语句的时候都重新生成一次快照(Read View),每次select查询时。
可重复读: 同一个事务开始的时候生成一个当前事务全局性的快照(Read View),第一次select查询时。

快照读取原则:

  1. 版本未提交无法生成快照
  2. 版本已提交,但是在快照创建后提交,无法读取
  3. 版本已提交,但是在快照创建前提交,可以读取
  4. 当前事务内自己更新,可以读到

在这里插入图片描述

InnoDB提供了两个读取操作:

  • 锁定读: S、X锁
  • 非锁定读: 其依赖于 undo log 回滚日志

undo log:回滚日志,保存了事务发生之前的数据的一个版本,用于执行时的回滚操作,同时也是实现多版本并发控制(MVCC)下的关键技术
在这里插入图片描述

redo log:重做日志,用于记录事务操作的变化,确保事务的持久性。redo log是在事务开始后就开始记录,不管事务是否提交都会记录下来,在异常发生时(如数据持久化过程中掉电),InnoDB会使用redo log恢复到掉电前的时刻,保证数据的完整性。InnoDB修改操作数据时,不是直接修改磁盘上的数据,实际只是修改Buffer Pool中的数据。InnoDB总是先把Buffer Pool中的数据改变记录到redo log中,用来进行崩溃后的数据恢复。 优先记录redo log,然后再由专门的线程将Buffer Pool中的脏数据刷新到磁盘上。
在这里插入图片描述

四、MySQL优化问题

对于MySQL优化问题分为3种:

  • SQL和索引的优化: 慢查询日志 -》 根据表的数据量等设置合理的慢查询时间 -》 记录慢查询sql -》 explain 分析sql执行计划 -》 优化措施
  • 应用上的优化:
    • 连接数据库:访问频繁,引入连接池中间件
    • 引入缓存(存储热点数据) redis(重点!!!)
      • 缓存数据一致性问题?
      • 缓存穿透
      • 缓存雪崩
      • redis还有哪些功能?
  • mysql server上的优化: 各种参数配置!
    • MySQL的查询缓存 query_cache_typequery_cache_size
    • 索引和数据缓存, innodb_buffer_pool_size越高,磁盘IO越少
    • MySQL线程缓存thread_cache_size
    • 并发连接数量和超时时间 max_connectionswait_timeout

五、总结

  • 事务的特征 ACID—— 原子性、一致性、隔离性、持久性
  • 事务并发的问题——脏读、不可重复度、虚读/幻读
  • 事务的隔离级别——未提交读、已提交读、可重复读、串行话
  • 锁的力度——行级锁、表级锁
  • 锁的分类——排他锁、共享锁(意向共享锁、意向排他锁)
  • 使用非索引字段获取排他锁时,实际上是直接加了表锁
  • 串行化解决的幻读问题——间隙锁(范围查询、等值查询)
  • 锁的优化建议——低隔离级别、设计合理索引、使用相同顺序、尽可能等值查询
  • 可重复读和已提交读隔离级别 通过MVCC机制中的快照读(非锁定读)保证,依赖于undo log回滚日志
  • MYSQL优化——sql和索引、应用层、mysql server

🌻🌻🌻以上就是有关于MySQL事务和锁机制的内容,如果聪明的你浏览到这篇文章并觉得文章内容对你有帮助,请不吝动动手指,给博主一个小小的赞和收藏 🌻🌻🌻

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/714610.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络编程-编码与解码(Protobuf)

编码与解码 下面的文字都来自于极客时间 为什么要编解码呢?因为计算机数据传输的是二进制的字节数据 解码:字节数据 --> 字符串(字符数据) 编码:字符串(字符数据)–> 字节数据 我们在编…

公共字段自动填充

在开发中经常面临对于一些公共字段的赋值。 如在下表中: 如何让程序自动为我们需要赋值的公共字段进行赋值,避免在业务代码中重复写这些公共字段的赋值代码 如下图所示: 实现思路: 1.自定义注解AutoFill,用于标识需…

linux环境安装cuda toolkit

1 全新安装 如果环境中没安装过cuda版本, 这种情况下比较简单。 直接在https://developer.nvidia.com/cuda-toolkit-archive选择对应版本下载安装即可。 如下为安装cuda toolkit 11.8. 2 环境中已经存在其他版本 这种情况下比较复杂一些。 首先要确认最高支持的…

李沐动手学习深度学习——4.2练习

1. 在所有其他参数保持不变的情况下,更改超参数num_hiddens的值,并查看此超参数的变化对结果有何影响。确定此超参数的最佳值。 通过改变隐藏层的数量,导致就是函数拟合复杂度下降,隐藏层过多可能导致过拟合,而过少导…

【MySQL】表的内连和外连(重点)

表的连接分为内连和外连。 一、内连接 内连接实际上就是利用 where 子句对两种表形成的笛卡儿积进行筛选,前面学习的查询都是内连接,也是在开发过程中使用的最多的连接查询。 select 字段 from 表1 inner join 表2 on 连接条件 and 其他条件; 注意&…

Linux使用基础命令

1.常用系统工作命令 (1).用echo命令查看SHELL变量的值 qiangziqiangzi-virtual-machine:~$ echo $SHELL /bin/bash(2).查看本机主机名 qiangziqiangzi-virtual-machine:~$ echo $HOSTNAME qiangzi-virtual-machine (3).date命令用于显示/设置系统的时间或日期 qiangziqian…

Linux多线程服务端编程:使用muduo C++网络库 学习笔记 附录B 从《C++ Primer(第4版)》入手学习C++

这是作者为《C Primer(第4版)(评注版)》写的序言,文中“本书”指的是这本书评注版。 B.1 为什么要学习C 2009年本书作者Stanley Lippman先生应邀来华参加上海祝成科技举办的C技术大会,他表示人们现在还用…

扩展学习|大数据分析的现状和分类

文献来源:[1] Mohamed A , Najafabadi M K , Wah Y B ,et al.The state of the art and taxonomy of big data analytics: view from new big data framework[J].Artificial Intelligence Review: An International Science and Engineering Journal, 2020(2):53. 下…

蓝桥杯(3.2)

1209. 带分数 import java.io.*;public class Main {static BufferedReader br new BufferedReader(new InputStreamReader(System.in));static PrintWriter pw new PrintWriter(new OutputStreamWriter(System.out));static final int N 10;static int n, cnt;static int[…

LabVIEW流量控制系统

LabVIEW流量控制系统 为响应水下航行体操纵舵翼环量控制技术的试验研究需求,通过LabVIEW开发了一套小量程流量控制系统。该系统能够满足特定流量控制范围及精度要求,展现了其在实验研究中的经济性、可靠性和实用性,具有良好的推广价值。 项…

tritonserver学习之八:redis_caches实践

tritonserver学习之一:triton使用流程 tritonserver学习之二:tritonserver编译 tritonserver学习之三:tritonserver运行流程 tritonserver学习之四:命令行解析 tritonserver学习之五:backend实现机制 tritonserv…

【C++初阶】内存管理

目录 一.C语言中的动态内存管理方式 二.C中的内存管理方式 1.new/delete操作内置类型 2.new和delete操作自定义类型 3.浅识抛异常 (内存申请失败) 4.new和delete操作自定义类型 三.new和delete的实现原理 1.内置类型 2.自定义类型 一.C语…

C++学习笔记:二叉搜索树

二叉搜索树 什么是二叉搜索树?搜索二叉树的操作查找插入删除 二叉搜索树的应用二叉搜索树的代码实现K模型:KV模型 二叉搜索树的性能怎么样? 什么是二叉搜索树? 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树: 若它的左子树…

Linux安装Nginx详细步骤

1、创建两台虚拟机,分别为主机和从机,区别两台虚拟机的IP地址 2、将Nginx素材内容上传到/usr/local目录(pcre,zlib,openssl,nginx) 附件 3、安装pcre库   3.1 cd到/usr/local目录 3.2 tar -zxvf pcre-8.36.tar.gz 解压 3.3 cd…

MATLAB图像噪声添加与滤波

在 MATLAB 中添加图像噪声和进行滤波通常使用以下函数: 添加噪声:可以使用imnoise函数向图像添加各种类型的噪声,如高斯噪声、椒盐噪声等。 滤波:可以使用各种滤波器对图像进行滤波处理,例如中值滤波、高斯滤波等。 …

前端学习、HTML

html是由一些标签构成的,标签之间可以嵌套,每个标签都有开始标签和结束标签,也有部分标签只有开始标签,没有结束标签。html的标签也可以成为元素。(树形结构) html文件的最顶层标签就是html。 head用来放…

**蓝桥OJ 178全球变暖 DFS

蓝桥OJ 178全球变暖 思路: 将每一座岛屿用一个颜色scc代替, 用dx[]和dy[]判断他的上下左右是否需要标记颜色,如果已经标记过颜色或者是海洋就跳过.后面的淹没,实际上就是哪个块上下左右有陆地,那么就不会被淹没,我用一个tag标记,如果上下左右一旦有海洋,tag就变为false.如果tag…

用冒泡排序模拟C语言中的内置快排函数qsort!

目录 ​编辑 1.回调函数的介绍 2. 回调函数实现转移表 3. 冒泡排序的实现 4. qsort的介绍和使用 5. qsort的模拟实现 6. 完结散花 悟已往之不谏,知来者犹可追 创作不易,宝子们!如果这篇文章对你们有帮助的话,别忘了给个免…

机器学习:模型评估和模型保存

一、模型评估 from sklearn.metrics import accuracy_score, confusion_matrix, classification_report# 使用测试集进行预测 y_pred model.predict(X_test)# 计算准确率 accuracy accuracy_score(y_test, y_pred) print(f"Accuracy: {accuracy*100:.2f}%")# 打印…

整数和浮点数在内存中的存储(大小端字节序,浮点数的存取)

目录 1.整数在内存中的存储 2.大小端字节序和字节序判断 2.1什么是大小端? 2.2为什么会有大小端 3.浮点数在内存中的存储 3.1浮点数的存储 3.1.1 浮点数存的过程 3.1.2 浮点数取的过程 3.2 解析 3.3 验证浮点数的存储方式 1.整数在内存中的存储 整数的二进…