《MySQL 事务深度解析:从 ACID 到实战,守住数据一致性的最后防线》

**前引:**数据是业务的核心,而事务是数据可靠性的 "守护神"。在 MySQL 中,事务看似简单的 "提交 / 回滚" 操作,背后藏着 ACID 特性的严格约束、隔离级别的底层实现,以及并发场景下的锁竞争逻辑。很多开发者因为一知半解,导致系统出现脏读、幻读、数据丢失等严重问题。今天,我们就来层层拆解 MySQL 事务,让你从 "会用" 到 "精通",真正守住数据一致性的底线!

目录

【一】事务介绍

【二】为什么要有事务

【三】事务的版本支持

【四】事务提交的两种方式

【五】事务的几种操作

(1)开始一个事务

(2)创建一个保存点

(3)回滚到指定保存点

(4)正常结束一个事务

(5)异常结束一个事务

【六】事务隔离级别

【七】事务相关结论

【八】修改事务隔离级别

【九】客户端会话与事务关系

【十】进阶:数据并发的场景

读-写


【一】事务介绍

事务是一组DML相关的语句(操作指令)集合,这些指令要么成功/不成功,满足如下性质:

  • 原子性(Atomicity):操作不可分割,要么全成要么全败
  • 一致性(Consistency):事务前后数据库完整性不被破坏
  • 隔离性(Isolation):并发事务互不干扰,避免脏读、幻读等问题
  • 持久性(Durability):事务提交后,数据修改永久有效

【二】为什么要有事务

事务是为了服务应用层而存在,数据库是存储数据的地方,那么应用层对数据进行的操作就必须保障数据的一致性,这些关心事情(比如我这次的修改数据会不会不成功、等下有没有可能就没有了)应该人性化的交给MySQL自己实现,因此它是一个服务机制(为应用层服务)

【三】事务的版本支持

在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务, MyISAM 不支持

cpp 复制代码
mysql> show engines;           -- 表格显示
mysql> show engines \G         -- 行显示

【四】事务提交的两种方式

事务的提交方式常见的有两种: 自动提交 和 手动提交

查看事务提交方式:

cpp 复制代码
show variables like 'autocommit';

用 SET 来改变 MySQL 的自动提交模式:

cpp 复制代码
SET AUTOCOMMIT=0;            #SET AUTOCOMMIT=0 禁止自动提交

SET AUTOCOMMIT=1;           #SET AUTOCOMMIT=1 开启自动提交

【五】事务的几种操作

(1)开始一个事务
cpp 复制代码
begin;
(2)创建一个保存点
cpp 复制代码
savepoint 自命名;
(3)回滚到指定保存点
cpp 复制代码
rollback to 保存点名字;
(4)正常结束一个事务

注意:正常结束一个事务后,不支持回滚

cpp 复制代码
commit;
(5)异常结束一个事务

注意:异常结束自动回滚,由于原子性,自动回到事务未提交时的数据状态

cpp 复制代码
Aborted;

【六】事务隔离级别

(1)**读未提交:**在该隔离级别,所有的事务都可以看到其他事务没有提交的 执行结果。(实际生产中不可能使用这种隔离级别的),但是相当于没有任何隔离性,也会有很多 并发问题,如脏读,幻读,不可重复读等!

理解:假设多个客户端并发访问操作同一个数据,单个客户端的任何操作不管提交与否,其它人都看的到

总结:不管对方提交与否,都看得到数据的修改

(2)**读提交:**该隔离级别是大多数数据库的默认的隔离级别(不是 MySQL 默 认的)。它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变。这种隔离级别会引起不可重复读,即一个事务执行时,如果多次 select, 可能得到不同的结果!

理解:假设A在操作一个事务,B也在操作一个事务

A和B都在修改表1,A在执行commit之前,B是看不到A做出的修改的

一但A做出了提交,B就可以看到A的修改

总结:只要对方提交了,哪怕是多个事务,数据修改就会被其它人看到

(3)**可重复读:**这是 MySQL 默认的隔离级别,它确保同一个事务,在执行中,多次读取操作数据时,会看到同样的数据行。但是会有幻读问题!

理解:假设A在操作一个事务,B也在操作一个事务

A和B如果操作同一个表,此时A完成了提交,B是看不到修改的,B看到的是B进入该事务开始时的数据,如果A退出事务了,那么B的数据就会更新到最新的

总结:只有单方提交且退出事务,对方才看得到更改

什么是幻读?假设A修改了张三的年龄,然后提交退出事务,B此时可能在筛选年龄时出现两个张三,因为A提交且退出事务了,B就会更新数据

(4)**串行化:**这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突, 从而解决了幻读的问题。它在每个读的数据行上面加上共享锁!

总结:一把锁,你访问数据是没有问题的,当你修改数据时,只有在你前一个事务修改完了你才可以执行修改的操作,即串行化,唯一就是效率低

【七】事务相关结论

(1)持久化保障:只要开始一个事务,输入begin或者start transaction,事务便必须要通过 commit提交,才会持久化,与是否设置自动提交无关

(2)事务可以手动回滚,同时,当操作异常,MySQL会自动回滚

以上可以看出事务的原子性和持久性:要么成功要么不成功,数据一经提交,就是持久化

而原子性保障了数据的一致性,

【八】修改事务隔离级别

  • 读未提交SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
  • 读提交SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
  • 可重复读 (默认):SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
  • 串行化SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;

【九】客户端会话与事务关系

客户端会话并非是一个事务,一个客户端中可以允许多个事务,事务之前相互独立

【十】进阶:数据并发的场景

数据并发场景有以下三种:

读-读 :不存在任何问题,也不需要并发控制

读-写 :有线程安全问题,可能会造成事务隔离性问题,可能遇到脏读,幻读,不可重复读

写-写 :有线程安全问题,可能会存在更新丢失问题,比如第一类更新丢失,第二类更新丢失

什么是读and读?读写、写写就自然明白了

多个用户访问同一块数据不存在安全问题,因为只访问不修改

读-写

用来解决读-写的方案:多版本并发控制( MVCC )(无锁并发控制)

解决问题:读写互不阻塞

如何解决?超易懂版本

MVCC依靠三个工具:

(1)数据的额外三个标签:最近修改的事务ID、回滚指针、隐式主键

(2)快照仓库(针对写操作):当修改数据时会保存一份原始数据在 undo 日志里面,回滚指针 指向该原始数据

(3)读视图(针对读操作):形成读视图,给当前事务划分可见范围,看不到未提交的或者在你 后面提交的数据版本

运行过程:当A去修改数据时,会加行锁(保证修改的原子性),先将原始数据放在 undo 仓库,如果有读端访问,访问的是 undo 仓库里面的,看不到A的修改,因为有视图范围,读写可以同时进行,视图通过划分范围可以自行屏蔽脏读------四种隔离性无非是对这三个工具"度"的把控

相关推荐
霖霖总总12 小时前
[小技巧69]为什么总说MySQL单表“别超 2000 万行”?一篇讲透 InnoDB 存储极限
数据库·mysql
安科士andxe13 小时前
实操指南|安科士1.25G CWDM SFP光模块选型、部署与运维全攻略
运维·数据库·5g
Java爱好狂.13 小时前
RDB&AOF持久化原理解析
java·数据库·redis·后端开发·java编程·java程序员·java八股文
蓝胖子Lcl13 小时前
Mac安装Oracle数据库(M芯片)
数据库·macos·oracle
砚边数影13 小时前
从文档型数据库到企业级数据平台:一次架构演进的思考与实践
数据库·mongodb·架构·kingbase·数据库平替用金仓·金仓数据库
SQL必知必会14 小时前
SQL 删除重复行完全指南
数据库·sql
工业甲酰苯胺14 小时前
spring-事务管理
数据库·sql·spring
全栈前端老曹14 小时前
【Redis】Redis 持久化机制 RDB 与 AOF
前端·javascript·数据库·redis·缓存·node.js·全栈
李慕婉学姐14 小时前
Springboot平安超市商品管理系统6sytj3w6(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端