Mysql3——事务原理

news2024/11/25 13:52:17

文章目录

  • Mysql3——事务原理
    • 1. 事务概念
    • 2. 隔离级别
    • 3. MVCC多版本并发控制
      • 3.1 read view
      • 3.2 事务可见性
      • 3.3 undo log
    • 4. InnoDB锁
      • 4.1 全局锁
      • 4.2 表级锁
      • 4.3 行级锁
      • 4.4 不同DML的加锁情况
      • 4.5 锁的对象
      • 4.6 锁的兼容性
    • 5. 死锁问题
      • 5.1 查看锁信息
      • 5.2 死锁原因
      • 5.3 死锁的解决
    • 学习参考

Mysql3——事务原理

本文讲述了mysql中事务的概念、原理,重点讲述了四种隔离级别、mvcc、锁以及死锁问题。

1. 事务概念

事务的定义:在数据库存在多个连接并发执行sql语句的场景下,由用户定义的一系列操作,这些操作要么都做,要么都不做,是一个不可分割的整体,其它线程不能访问中间状态。

事务语句:

开启事务:

begin/start transaction;

回滚事务:

rollback;

提交事务:

commit;

如果不写begin和commit,那么每一条sql语句都会被作为一个事务执行。

事务特性:

  • 原子性,由undolog保证,保证一系列操作要么全部执行,要么回滚到执行前的状态。
  • 一致性,保证操作前后数据库满足完整性约束以及用户逻辑上定义的约束条件。例如对于银行转账业务,事务发生前后银行的总余额应该不变。
  • 隔离性,保证多个连接并发执行的事务互不干扰,防止交叉执行导致数据不一致。通过锁和MVCC来实现。为了提高并发性能,适当破坏逻辑上的一致性,设置了四种隔离级别:对同一块区域的写操作需要串行执行,对于读操作进行优化。
  • 持久性,由redolog保证,在事务提交时会将所作的修改操作写入到redolog并刷入磁盘。

2. 隔离级别

  1. read uncommitted(读未提交)

    读:不做任何处理

    写:自动加x锁

  2. read committed(读已提交)

    读:mvcc,读取最新版本的行数据

    写:自动加x锁

  3. repeatable read(可重复读)默认隔离级别

    读:mvcc,保证多次读取的同一行数据一致

    写:自动加x锁,额外加锁

  4. serializable(可串行化)

    读:自动加S锁(next-key lock)

    写:自动加x锁

不同隔离级别的并发异常

  • 脏读:一个事务读到另一个事务未提交修改的数据,及一个事务能看到另一个事务的中间状态。

    原因:读取的数据被另一个事务修改了,但是还没提交。

    解决方式:将隔离级别提升未可重复读。

  • 不可重复读:一个事务内同一行记录读到两次不一样的数据。

    原因:在两次读取之间,另一个事务修改并且提交了同一行数据。

    解决方式:将隔离级别提升到可重复读。

  • 幻读:同一事务中,同一查询条件下两次读取到的结果集不一致。

    原因:两次查询之间另一事务的插入、删除或者修改了数据记录。当前读和快照读的不一致。写操作使用当前读而读操作使用快照读。

    解决方式:提升至可串行化,或者使用FOR SHARE或FOR UPDATE为读操作加锁。

  • 丢失更新:在任何隔离级别都可能发生,除非完全串行化。

相关DCL

-- 设置隔离级别
SET [GLOBAL | SESSION] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE];

-- 查看全局隔离级别
SELECT @@global.transaction_isolation;
-- 查看当前会话隔离级别
SELECT @@session.transaction_isolation;

-- 手动给读操作加S锁
SELECT ... [LOCK IN SHARE MODE | FOR SHARE];
-- 手动给读操作加X锁
SELECT ... FOR UPDATE;
-- 查看当前锁信息
SELECT * FROM information_schema.innodb_locks;

如何在可重复读的隔离级别下解决幻读问题?

幻读是指在同一事务中,针对同一查询条件执行两次查询时,其结果集不一致,这些变化是由于其他事务在两次查询之间插入、删除或修改了数据导致的。

可以手动为查询操作加锁,从而避免在两次查询之间,其它事务修改数据。

SELECT * FORM `employees` WHERE `salary` > 1000 [FOR UPDATE|FOR SHARE];

不可重复读与幻读的区别

  • 不可重复读:同一行数据被修改导致读取结果不一致。
  • 幻读:表中符合条件的行数或内容发生变化,而不是单一行数据的值变化。

3. MVCC多版本并发控制

MVCCMulti-Version Concurrency Control,多版本并发控制)它通过为每个事务创建一致性视图和undo log中保存的多版本的记录,来实现一致性非锁定读。非锁定读是指不需要等待访问的行上X锁的释放;

MVCC主要是通过read view事务视图实现的。

3.1 read view

mvcc实现原理:MVCC使用read view确定哪个版本的数据对当前事务可见,生成”快照“,实现一致性非锁定读。

在两个隔离级别中的区别在于创建read view的时机不同:

  • read committed下MVCC会为事务的每个select都生成一个read view,这意味着同一事务多次读取同一条数据可能出现不一致。
  • repeatable read下MVCC只会在第一次查询时创建一个read view,在整个事务期间都使用这个read view,

read view的构成:

  • **m_ids:**当前活跃事务 ID 列表:当前数据库中所有未提交事务的事务 ID 列表。用于确定哪些事务是活跃的,哪些事务对当前事务不可见。

  • **min_trx_id:**最小活跃事务 ID:活跃事务 ID 列表中最小的事务 ID。用于标识最早的未提交事务。

  • **max_trx_id:**最大已分配事务 ID:在生成 Read View 时分配的最大事务 ID。所有事务 ID 小于这个值的事务已被创建。

  • **creator_trx_id:**当前事务 ID:创建当前 Read View 的事务 ID。

3.2 事务可见性

read view的主要功能就是确定哪个版本的数据记录对于事务可见。

聚集索引数据记录的隐藏列

  • **trx_id:**当某个事务对某条聚集索引记录进行修改时,将会把当前事务的 id 赋值给 trx_id ;
  • **roll_pointer:**当某个事务对某条聚集索引记录进行修改时,会将上一个版本的记录写到 undo log,然后通过 roll_pointer 指向旧版本记录,通过它可以找到修改前的记录;

事务的可见性

  • trx_id < min_trx_id :说明该记录在创建 read_view 之前已经提交,所以对当前事务可见;
  • trx_id >= max_trx_id:说明该记录是在创建 read_view 之后启动事务生成的,所以对当前事务 不可见;
  • min_trx_id <= trx_id < max_trx_id :此时需要判断是否在 m_ids 列表中;
    • 在列表中:生成该版本记录的事务仍处于活跃状态,该版本记录对当前事务不可见;
    • 不在列表中:生成该版本记录的事务已经提交,该版本记录对当前事务可见;

3.3 undo log

undo log保存旧版本数据实现MVCC。

undo 日志用来帮助事务回滚以及 MVCC 的功能;存储在共享表空间中;undo 是逻辑日志,回滚时 将数据库逻辑地恢复到原来的样子,根据 undo log 的记录,做之前的逆运算;比如事务中有 insert 操作,那么执行 delete 操作;对于 update 操作执行相反的 update 操作;
同时 undo 日志记录行的版本信息,用于处理 MVCC 功能;

4. InnoDB锁

MySQL当中事务采用三种粒度的锁:针对表(B+树)、页(B+树叶子节点)、行(叶子节点中某个记录)三种。

根据加锁的范围可分为全局锁、表级锁、行级锁,innodb主要使用行级锁保证事务的隔离性。其中行级锁又可分为记录锁、间隙锁、意向插入锁和临键锁。

根据锁的功能可分为共享锁(S锁)、排他锁(X锁)、意向共享锁、意向排他锁、auto_incre锁。

4.1 全局锁

主要用于数据库备份

flush tables with read lock;	# 使整个数据库处于只读状态
unlock tables;	# 解锁

4.2 表级锁

MyIsam采用表级锁。

InnoDB中的表级锁类型:

  • 表锁

    lock tables `table_name` [read | write];
    unlock tables;
    
  • 元数据锁

    crud, alter

  • 意向锁:目的是快速判断是否有记录已被加锁,除了全表扫描操作外,不会阻塞其它行级锁。

  • auto_inc自增锁:特殊锁,主要是为了实现自增约束,语句结束后释放锁

4.3 行级锁

  1. 记录锁(record lock):针对一条数据记录加锁,分为S锁和X锁;RC级别下面使用。InnoDB引擎通过索引来实现记录锁。
  2. 间隙锁(gap lock):锁定一个范围,不包含记录,解决幻读问题。RR级别下面使用。即使查询没有匹配到任何记录,InnoDB 仍会锁住查询范围的间隙,以防止其他事务插入新数据。全开区间。
  3. 临键锁(next-key lock): 记录锁和间隙锁的结合,既锁住当前记录,也锁住其查询范围的间隙。也是主要在RR隔离界别下使用。左开右闭区间。
  4. 意向插入锁(insert intention lock):只会在插入操作中临时加锁,并且不会阻止其他事务对间隙内非冲突位置的插入操作。

4.4 不同DML的加锁情况

查询操作

  1. 如果隔离级别时RC或者RR,并且没有手动加锁,则使用mvcc进行读快照数据。
  2. 使用lock in share mode或者for share,加S锁
  3. 使用for update,加X锁
  4. 在RU隔离级别下,查询操作不加任何锁

删除、更新

  1. 自动加X锁

插入

  1. 自动加x锁。
  2. 插入意向锁,一种特殊的间隙锁,表示事务打算在某个间隙中插入一条记录。

插入意向锁(Insert Intention Lock)插入意向锁是一种 临时的间隙锁。只会在插入操作中临时加锁,并且不会阻止其他事务对间隙内非冲突位置的插入操作。插入意向锁是对间隙锁机制的一种优化,用于处理多事务并发插入的情况。它通过降低锁冲突来提高并发性能,同时保持一致性。

  1. auto_inc lock自增锁,特殊的表级锁。

4.5 锁的对象

讨论一下不同隔离级别下执行update操作回对聚集索引和辅助索引分别加什么锁。

update `table_name` set `filed` = val where `field2` = val2;
  • 聚集索引

    • 如果查询命中,RC和RR是一样的,都对数据加记录锁
    • 如果查询未命中,RC不加锁,RR会在查询范围加间隙锁
  • 辅助唯一索引

    • 如果查询命中,RR和RC一样,对辅助索引和对应聚集索引的行加记录锁。(RR进行了锁降级Next-key lock --> Record lock)
    • 如果查询未命中,RC不加锁,RR对辅助索引的查询范围加间隙锁,不对聚集索引加锁,防止幻读。
  • 辅助非唯一索引

    • 如果命中,RC对命中的辅助索引和聚集索引加记录锁,RR对辅助索引加间隙锁,对聚集索引加记录锁。
    • 如果未命中,RC不加锁,RR对辅助索引加间隙锁,不对聚集索引加锁。
  • 无索引

    不使用索引时,innoDB无法快速定位记录的范围,因此会进行更加严格的加锁,整张表可能会被大量间隙锁和记录锁覆盖,实际效果接近表锁。

    • 没有命中时,RC对每个记录加记录锁,而RR不仅对每个记录加锁,而且对每个间隙加间隙锁。

4.6 锁的兼容性

锁类型S锁X锁IS锁IX锁AI锁
S锁✔️✔️✔️
X锁
IS锁✔️✔️✔️✔️
IX锁✔️✔️✔️
AI锁✔️✔️✔️
  1. 意向锁不会阻塞行级锁,只会阻塞表级读锁和表级写锁,以及全表扫描。
  2. 意向锁之间相互兼容
  3. IS锁只对X锁不兼容
  4. 当事务试图读或者写某一条记录时,会现在表上加上意向锁,然后才在要操作的记录上加上读锁或者写锁。

意向锁是表级锁,不会阻塞行级锁,行级锁只会与行级锁冲突。

5. 死锁问题

5.1 查看锁信息

# 查看系统中事务的状态
select * from information_schema.innodb_trx\G

# 查看系统中锁的信息
select * from performance_schema.data_locks\G

# 查看系统中正在等待的锁的信息
select * from performance_shcema.data_lock_waits\G

5.2 死锁原因

死锁:两个或两个以上的事务在执行语句的过程中因为争夺锁资源而相互等待的情况。Mysql采用wait-for graph(采用非递归深度优先的图算法实现)方式来进行死锁检测。

死锁原因

  1. 相反的加锁顺序,解决方式:有序加锁,每个连接加锁的顺序一致
  2. 锁不兼容,当前事务持有了待插入记录的下一个记录 的X锁,但是在等待队列中存在一个S锁的请求,则可能会发生死锁。

InnoDB在检测到死锁后会马上回滚一个事务。

5.3 死锁的解决

  • 尽可能以相同顺序来访问索引记录和表;
  • 如果能确定幻读和不可重复读对应用影响不大,考虑将隔离级别降低为 RC;
  • 添加合理的索引,不走索引将会为每一行记录加锁,死锁概率非常大;
  • 尽量在一个事务中只锁定所需要的资源,减小死锁概率;
  • 避免大事务,将大事务分拆成多个小事务;
  • 大事务占用资源多,耗时长,冲突概率变高;
  • 避免同一时间点运行多个对同一表进行读写的语句

学习参考

学习更多相关知识请参考零声 github。

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

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

相关文章

Python 版本的 2024详细代码

2048游戏的Python实现 概述&#xff1a; 2048是一款流行的单人益智游戏&#xff0c;玩家通过滑动数字瓷砖来合并相同的数字&#xff0c;目标是合成2048这个数字。本文将介绍如何使用Python和Pygame库实现2048游戏的基本功能&#xff0c;包括游戏逻辑、界面绘制和用户交互。 主…

spf算法、三类LSA、区间防环路机制/规则、虚连接

1.构建spf树&#xff1a; 路由器将自己作为最短路经树的树根根据Router-LSA和Network-LSA中的拓扑信息,依次将Cost值最小的路由器添加到SPF树中。路由器以Router ID或者DR标识。广播网络中DR和其所连接路由器的Cost值为0。SPF树中只有单向的最短路径,保证了OSPF区域内路由计管不…

(二)手势识别——动作模型训练【代码+数据集+python环境(免安装)+GUI系统】

&#xff08;二&#xff09;手势识别——动作模型训练【代码数据集python环境&#xff08;免安装&#xff09;GUI系统】 背景意义 随着互联网的普及和机器学习技术的进一步发展&#xff0c;手势识别技术开始使用深度学习等方法进行手势识别&#xff0c;如Convolutional Neural…

React的基本知识:事件监听器、Props和State的区分、改变state的方法、使用回调函数改变state、使用三元运算符改变state

这篇教学文章涵盖了大量的React基本知识。 包括&#xff1a; 事件监听器Props和State的区分改变state的方法使用回调函数改变state使用三元运算符改变state处理state中的数组处理state中的object条件渲染 &&条件渲染 三元运算符React中的forms 1. Event Listeners 在…

JavaScript练习——文本与图形

要求实现下面这个效果&#xff1a; 观察图片&#xff0c;我们的需求如下&#xff1a; 准备画布和上下文&#xff1a;在开始绘制之前&#xff0c;需要有一个HTML5 <canvas> 元素&#xff0c;并且获取其绘图上下文&#xff08;context&#xff09;&#xff0c;这是进行绘图…

【线程】线程安全问题及解决措施

【线程】线程安全问题及解决措施 前言一、由“随机调度”引起的线程安全问题1.1现象1.2 原因1.3 解决办法1.4 不当加锁造成的死锁问题 二、由“系统优化”引起的线程安全问题2.1 内存可见性问题 / 指令重排序问题2.2 解决方案 前言 何为线程安全&#xff0c;即某段代码无论在单…

[开源]3K+ star!微软Office的平替工具,跨平台,超赞!

大家好&#xff0c;我是JavaCodexPro&#xff01; 数字化的当下&#xff0c;高效的办公工具是提升工作效率的关键&#xff0c;然而大家想到的一定是 Microsoft Office 办公软件&#xff0c;然而价格也是相当具有贵的性价比。 今天JavaCodexPro给大家分享一款超棒的开源办公套…

【大数据分析机器学习】分布式机器学习

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈智能大数据分析 ⌋ ⌋ ⌋ 智能大数据分析是指利用先进的技术和算法对大规模数据进行深入分析和挖掘&#xff0c;以提取有价值的信息和洞察。它结合了大数据技术、人工智能&#xff08;AI&#xff09;、机器学习&#xff08;ML&a…

SOL链上的 Meme 生态发展:从文化到创新的融合#dapp开发#

一、引言 随着区块链技术的不断发展&#xff0c;Meme 文化在去中心化领域逐渐崭露头角。从 Dogecoin 到 Shiba Inu&#xff0c;再到更多细分的 Meme 项目&#xff0c;这类基于网络文化的加密货币因其幽默和社区驱动力吸引了广泛关注。作为近年来备受瞩目的区块链平台之一&…

一篇保姆式centos/ubuntu安装docker

前言&#xff1a; 本章节分别演示centos虚拟机&#xff0c;ubuntu虚拟机进行安装docker。 上一篇介绍&#xff1a;docker一键部署springboot项目 一&#xff1a;centos 1.卸载旧版本 yum remove docker docker-client docker-client-latest docker-common docker-latest doc…

Dubbo源码解析-Dubbo的线程模型(九)

一、Dubbo线程模型 首先明确一个基本概念&#xff1a;IO 线程和业务线程的区别 IO 线程&#xff1a;配置在netty 连接点的用于处理网络数据的线程&#xff0c;主要处理编解码等直接与网络数据 打交道的事件。 业务线程&#xff1a;用于处理具体业务逻辑的线程&#xff0c;可以…

前端全栈 === 快速入 门 Redis

目录 简介 通过 docker 的形式来跑&#xff1a; set、get 都挺简单&#xff1a; incr 是用于递增的&#xff1a; keys 来查询有哪些 key: redis insight GUI 工具。 list 类型 left push rpush lpop 和 rpop 自然是从左边和从右边删除数据。​编辑 如果想查看数据…

Python MySQL SQLServer操作

Python MySQL SQLServer操作 Python 可以通过 pymysql 连接 MySQL&#xff0c;通过 pymssql 连接 SQL Server。以下是基础操作和代码实战示例&#xff1a; 一、操作 MySQL&#xff1a;使用 pymysql python 操作数据库流程 1. 安装库 pip install pymysql2. 连接 MySQL 示例 …

编程语言之C++诞生记!

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C诞生的相关内容&#xff01; 关于【C诞…

核心差异:知识VS文档管理(+工具软件安利)

在讨论知识管理和文档管理时&#xff0c;我们经常会听到这两种说法被混淆使用。然而&#xff0c;它们各自服务于不同的目的&#xff0c;这一点至关重要。 想象一下&#xff0c;你是一名项目经理&#xff0c;面临以下两项任务&#xff1a; 存储最新的项目计划捕捉团队讨论中获…

医院挂号就诊系统(源码+数据库+报告)

基于SpringBoot的医院挂号就诊系统&#xff0c;系统包含三种角色&#xff1a;管理员、医生、用户,系统分为前台和后台两大模块&#xff0c;主要功能如下。 前台&#xff1a; - 首页&#xff1a;展示医院相关信息、推荐医生等内容。 - 健康教育&#xff1a;提供健康知识、文章等…

【热门主题】000065 探索人工智能学习框架:开启智能未来的钥匙

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【热…

《智慧教育实时数据分析推荐项目》详细分析

一、项目介绍 1、背景介绍 在互联网、移动互联网的带动下&#xff0c;教育逐渐从线下走向线上&#xff0c;在线教育近几年一直处于行业的风口浪尖&#xff0c;那随着基础设施的不断完善&#xff0c;用户需求也发生不少变化&#xff0c;因此传统教育机构、新兴互联网企业都在探…

使用LUKS对Linux磁盘进行加密

前言 本实验用于日常学习用&#xff0c;如需对存有重要数据的磁盘进行操作&#xff0c;请做好数据备份工作。 此实验只是使用LUKS工具的冰山一角&#xff0c;后续还会有更多功能等待探索。 LUKS&#xff08;Linux Unified Key Setup&#xff09;是Linux系统中用于磁盘加密的一…

在 cmd 输入 python.exe 后不报错也无反应的问题

在 cmd 输入 python.exe 后不报错&#xff1a;‘python.exe ’不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件&#xff0c;也无反应。只是显示这样一个弹窗&#xff1a; 查了下环境变量path&#xff0c;看看有什么地方有python.exe&#xff0c;发现原来在C:\Us…