掌握 MySQL 事务:ACID、隔离级别详解

server/2024/12/14 16:17:21/

一、前言

  • 事务是关系型数据库中的重要概念,用于保证一组数据库操作作为一个单独的工作单元来执行。无论是银行转账、订单处理还是复杂的数据修改,事务都能保证操作的一致性和完整性。

  • 本文将带您从基础概念到高级技巧,全面了解 MySQL 事务的工作原理、使用方法和优化策略。

二、事务基础

什么是事务?

  • 定义:事务是一组操作的集合,这些操作要么全部执行,要么全部不执行。

  • 事务的目的:确保数据库操作的一致性、完整性、隔离性和持久性(ACID 属性)。

事务的 ACID 属性

原子性 (Atomicity)

事务是不可分割的最小操作单位,要么全部执行,要么全部不执行。主要是commit、rollback、autocommit来保证原子性。

一致性 (Consistency)

所谓一致性,就是保证数据的一致,也就是保证数据不要丢失,不会因为突然的断电等导致数据与想要的数据不一致。主要体现在:

  1. 双写 保证内存跟磁盘之间同步的数据安全

  2. 基于RedoLog的数据恢复

隔离性 (Isolation)一个事务的执行不应受其他事务的干扰。主要体现在:

  1. 事务的隔离级别

  2. InnoDb的锁机制

持久性 (Durability)

一旦事务提交,对数据库的修改是永久性的,即使系统崩溃也不会丢失。InnoDB去保证持久性主要体现在:

  1. 双写 保证内存同步到磁盘,就算page损坏的情况下也能恢复

  2. RedoLog的同步机制

  3. binlog的同步机制

事务的开启提交回滚

START TRANSACTION -- 开始一个事务。
COMMIT -- 提交事务,保存所有的更改。
ROLLBACK -- 回滚事务,撤销事务中的所有更改。

自动提交

大家想一下我们平时写sql为什么没加上面的那些事务语句呢?这是因为我们Mysql里面,Mysql默认以自动提交模式运行的,简单来讲,就是每个语句,当没有START TRANSACTION开启事务的时候,每个语句都默认START TRANSACTION、commit包围,并且不能用ROLLBACK来回滚。但是如果执行期间发生了错误,则进行回滚。

查询是否开启自动提交

show SESSION VARIABLES like 'autocommit'; -- 查询(会话)是否开启自动提交
show GLOBAL VARIABLES like 'autocommit'; -- 查询(全局)自动开启提交

三、MySQL 中事务

大家想想,如果没有事务,数据的查询会有哪些问题呢?

数据一致性问题

脏读: 能读取到其他线程还没有提交的数据;但是这些数据可能是会回滚的。

不可重复读: 在开启事务之后,读取到其他事务进行修改或者删除提交的的数据。

幻读: 在开启事务之后,读到了其他事务新添加的新数据。

非锁定一致性读取(MVCC,快照读)

既然有上面那些问题,那么我们看看mysql是怎么解决这些问题的,首先我们需要先来了解几个知识点。

事务的隔离级别

  1. READ UNCOMMITTED:最低隔离级别,允许事务读取未提交的数据(脏读)。

  2. READ COMMITTED:保证事务只能读取已提交的数据,避免脏读,但可能会发生不可重复读。

  3. REPEATABLE READ:事务中的查询在整个事务期间保持一致,避免了不可重复读,但可能会有幻读。(innodb默认事务隔离级别)

  4. SERIALIZABLE:最高隔离级别,强制事务串行执行,避免所有并发问题,但性能开销大。

ReadView结构

m_low_limit_id:即将要分配的下一个事务ID。

m_up_limit_id:所有存活的(没有提交的)事务ID中最小值。

m_creator_trx_id:创建这个readView的事务ID。

m_ids:创建readView时,所有存活的事务ID列表。

行隐藏字段

DB_TRX_ID:更新这行数据的事务ID。

DB_ROLL_PTR :回滚指针,被改动前的undolog日志指针。

判断是否可见逻辑

有了上面几个知识点,我们来看看ReadView怎么跟我的行数据的DB_TRX_ID来配合 做到解决我的不可

重复读或者幻读问题呢?(这里就不画图了,画图太复杂了,大家多理解下下面的规则)

  1. 如果数据的DB_TRX_ID < m_up_limit_id, 都小于存活的事务ID了,那么肯定不存活了,说明在创建ReadView的时候已经提交了,可见。意思就是,A事务已经提交了,B事务才开始查询,那么肯定可以查询到最新的数据。

  2. 如果数据的DB_TRX_ID >=m_low_limit_id, 大于等于我即将分配的事务ID, 那么表明修改这条数据的事务是在创建了ReadView之后开启的,不可见。

  3. 如果 m_up_limit_id<= DB_TRX_ID< m_low_limit_id, 表明修改这条数据的事务在第一次快照之前就创建好了,但是不确定提没提交,判断有没有提交,直接可以根据活跃的事务列表 m_ids判断

DB_TRX_ID如果在m_ids中,表面在创建ReadView之时还没提交,不可见

DB_TRX_ID如果不在m_ids,表面在创建ReadView之时已经提交,可见

UndoLog日志查询以往版本的数据

所谓UndoLog,也就是回滚日志,简单点,当我需要回滚的时候,能找到之前相关的数据。比如,我们rollback或者异常中断的时候,能找到改动之前的数据进行恢复。当然,我们在mvcc中也需要用到undolog来找到以往的数据来解决不可重复读跟幻读问题。

那么undolog到底怎么记录的,我们来看下面这个图:

四、事务的并发控制

锁机制

**行级锁 (Row-level Lock)**:InnoDB 默认使用行级锁,它允许更多的并发操作,减少锁冲突。

**表级锁 (Table-level Lock)**:MyISAM 使用表级锁,可能导致较大的锁竞争。

锁的类型

记录锁(Record Locks)

记录锁,顾名思义,是锁在索引记录上的锁,索引扫描某些数据的时候,在这些索引数据上加锁。

SELECT * FROM user where id=1 FOR UPDATE; -- 索引扫描到id=1的数据,那么会锁id=1的数据,其他事务不能进行操作

间隙锁(Gap Locks)

间隙锁是对索引记录之间的间隙的锁。所谓间隙,就是索引数据之间的间隙,那么间隙锁,就是锁住数据之间的间隙,不允许间隙之内添加数据。看看下面的例子:

SELECT * FROM user where id > 1 AND id < 5 FOR UPDATE; -- 这里因为没有命中索引,所以索引1 和 5 之间不能添加id为2,3,4的数据

临键锁(Next-Key Locks)

临键锁是索引记录上的记录锁和索引记录之前的间隙上的间隙锁的组合。就是我扫描的数据,既包含索引中存在的数据,又是扫描的一个区间。看看下面的例子:

SELECT * FROM user where id > 4 AND id < 8 FOR UPDATE; -- 这里命中了索引4,所以索引1 和 5 之间和5和9之间不能添加id为2,3,4,6,7,8的数据,并且id=4这条数据不能修改

五、总结

  • 事务是 MySQL 数据库中重要的概念,它保证了操作的原子性、一致性、隔离性和持久性(ACID 属性)。

  • MySQL 提供了丰富的事务控制功能,包括事务隔离级别、锁机制、死锁检测等。


最后。


http://www.ppmy.cn/server/150134.html

相关文章

AI开源南京分享会回顾录

AI 开源南京分享会&#xff0c;已于2024年11月30日下午在国浩律师&#xff08;南京&#xff09;事务所5楼会议厅成功举办。此次活动由 KCC南京、PowerData、RISC-Verse 联合主办&#xff0c;国浩律师&#xff08;南京&#xff09;事务所协办。 活动以“开源视角的 AI 对话”为主…

docker简单私有仓库的创建

1&#xff1a;下载Registry镜像 导入镜像到本地中 [rootlocalhost ~]# docker load -i registry.tag.gz 进行检查 2&#xff1a;开启Registry registry开启的端口号为5000 [rootlocalhost ~]# docker run -d -p 5000:5000 --restartalways registry [rootlocalhost ~]# dock…

了解ARM的千兆以太网——RK3588

1. 简介 本文并不重点讲解调试内容&#xff0c;重点了解以太网在ARM设计中的框架以及在设备树以及驱动的一个整体框架。了解作为一个驱动开发人员当拿到一款未开发过的ARM板卡应该怎么去把网卡配置使用起来。 2. 基础知识介绍 在嵌入式ARM中实现以太网的解决方案通常有以下两种…

C++----入门篇

引言 C是在C的基础之上&#xff0c;容纳进去了面向对象编程思想&#xff0c;并增加了许多有用的库&#xff0c;以及编程范式等。熟悉C语言之后&#xff0c;对C学习有一定的帮助&#xff0c;本章节主要目标&#xff1a; 1. 补充C语言语法的不足&#xff0c;以及C是如何对C语言…

OpenCV 图像处理(一)

本章为 OpenCV 图像入门&#xff0c;主要讲解了如何加载图片&#xff0c;显示图片和保存图片。 读取图像 使用 cv.imread() 函数读取一张图像。 cv.IMREAD_COLOR&#xff1a;加载彩色图像&#xff0c;任何图像的透明度都会被忽略&#xff0c;它是默认标志&#xff1b;cv.IMRE…

网安加·百家讲坛 | 王立杰:质量与卓越:在DevOps中平衡开发速度与产品质量

作者简介&#xff1a;王立杰&#xff0c;资深敏捷创新教练、IDCF(国际DevOps教练联合会)联合发起人、华为云MVP、中国DevOps社区发起人&#xff0c;曾任京东首席敏捷创新教练、IBM客户技术专家&#xff0c;江湖人称“无敌哥”&#xff1b;最新著作《敏捷无敌之DevOps时代》、《…

KV Cache量化技术详解:深入理解LLM推理性能优化

在大模型技术快速发展的浪潮中&#xff0c;LLM的私有化部署与应用已成为各行业的刚需。然而&#xff0c;随着企业深入探索大模型应用场景&#xff0c;GPU资源消耗所带来的高昂部署成本&#xff0c;始终是制约大模型落地的关键瓶颈。特别是在需要进行模型训练和微调的特定领域应…

docker安装、升级、以及sudo dockerd --debug查看启动失败的问题

1、docker安装包tar下载地址 Index of linux/static/stable/x86_64/ 2、下载tgz文件并解压 tar -zxvf docker-24.0.8.tgz 解压后docker文件夹下位docker相关文件 3、将老版本docker相关文件&#xff0c;备份 将 /usr/bin/docker下docker相关的文件&#xff0c;mv到备份目录…