MySQL 事务入门:从案例到 ACID 特性,一文搞懂数据库可靠性保障

目录

事务案例

什么是事务

MySQL执行事务的语法

开启事务

提交事务

回滚(撤销)事务

案例

事务的特性和实现

特性

原子性

持久性

隔离性

一致性

并发事务出现的问题

脏读

不可重复读

幻读

丢失修改

事务隔离级别

读未提交(READ UNCOMITTED,RU)

读已提交(READ COMMITTED,RC)

可重复读(REPEATABLE READ,RR)

串行化(SERIALIZABLE)


小编之前介绍了微服务架构下的事务管理挑战及解决方案,而微服务中的分布式事务,本质是由多个数据库的 “本地事务” 协同组成的 —— 要搞懂复杂的分布式事务,得先把单机 MySQL 的事务基础打牢。今天小编就先来讲 MySQL 事务的核心特性与实践要点,我们来通过一个案例,更具象化地体现为什么需要事务。🌰🌰🌰🌰🌰🌰🌰🌰

事务案例

我们简单地创建了一个my_bank表,里面只有两个字段用户名·name,金额money。

从表中数据可以看出,小白和小新两个账户的余额总和为1001元

从小新的账户直接转账500元到小白的账户,使用UPDATE语句分别修改他们的账户,如下:

UPDATE my_bank SET money=money-500 WHERE NAME='小新';
UPDATE my_bank SET money=money+500 WHERE NAME='小白';

正常情况下,执行以上的转账操作后,余额总和应保持不变,仍为1001元。

但是,如果在这个过程中其中一个环节出现差错,例如在小新的账户减少500元之后,发生了服务器故障,小白的账户没有立即增加500元,此时,第三方读取到两个账户的余额总和变为500+1=501元,那账户总额就少了500元.....

什么是事务

MySQL为了解决此类问题,提供了事务。事务可以将一系列的数据操作捆绑成一个整体进行统一管理,如果某一事务执行成功,则在该事务中进行的所有数据更改均会提交,成为数据库中的永久组成部分。如果事务执行时遇到错误,则就必须取消或回滚。取消或回滚后,数据将全部恢复到操作前的状态,所有数据的更改均被清除。

MySQL执行事务的语法

默认设置下,每条SQL语句就是一个事务,即执行SQL语句后自动提交。为了达到将几个操作作为一个整体的目的,需使用BEGIN START TARNSACTION 开启一个事务

开启事务

这个语句显示地标记一个事务的起始点

BEGIN;
# 或者
START TRANSACTION;

提交事务

COMMIT表示提交事务,即提交事务的所有操作,将事务中的所有对数据库地更新都写到磁盘上地物理数据库中,因此也标志着一个事务地结束。一旦执行了该命令,将不能回滚事务。只有在所有修改都准备好提交给数据库时,才执行这一操作

COMMIT

回滚(撤销)事务

当事务执行过程中遇到错误时,使用ROLLBACK语句使事务回滚到起点或指定的保持点处。同时,系统将清除自事务起点或到某个保存点所做的所有的数据修改,并且释放由事务控制的资源。因此,这条语句也标志着事务的结束

ROLLBACK;

案例

在上一个栗子中,小新的账户余额已经减少到500元,如果再转出1000元,将会出现余额为负数,因此需要回滚到原始状态。

BEGIN;
UPDATE my_bank SET money=money-1000 WHERE NAME='小新';
ROLLBACK;

回滚后,查询账户信息,从结果可以看出,执行事务回滚后,账户数据恢复到初始状态,即该事务执行之前的状态

所以我们通过事务确保数据库操作的可靠性、一致性和完整性,避免因系统故障(如断电、网络中断)、操作错误或并发冲突导致的数据混乱。接下来我们来深入了解事务的特性

事务的特性和实现

任何一种数据库,都会拥有各种各样的日志,用来记录数据库的运行情况、日常操作、错误信息。例如,当用户root登录到MySQL服务器,就会在日志文件里记录该用户的登录时间、执行操作等。

  • UNDO Log日志:记录事务执行前的数据,用于在事务发生异常时回滚数据,以此来确保数据的原子性;
  • REDO Log日志:记录在事务执行中,每条对数据进行更新的操作,当事务提交时,该内容被刷新到磁盘。当MySQL意外宕机,InnoDB存储引擎会使用REDO Log恢复,以此来确保数据的持久性;

特性

事务具有 4 个特性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)。这 4 个特性通常简称为 ACID。

原子性

原子性确保事务是一个不可分割的工作单位,事务中的所有操作要么全部成功提交,要么在发生错误全部回滚

实现原理:InnoDB通过undo log(回滚日志)实现原子性。当事务执行修改操作时,InnoDB会记录数据的原始状态到undo log。若事务需要回滚,系统可通过undo log恢复数据至修改前状态

持久性

持久性保证事务一旦提交,其修改会永久保存到数据库中,即使发生系统崩溃,断电等故障也不会丢失

实现原理:InnoDB通过redo log(重做日志)实现持久性。事务执行时,修改操作先写入redo log缓冲区,定期刷新到磁盘。即使数据页未写入磁盘,重启后可以通过redo log恢复已提交的事务

隔离性

隔离性控制多个并发事务之间的相互影响,防止因并发执行,引发的数据不一致。隔离级别越高,数据一致性越好,但并发性能越低

实现原理:隔离性是通过MVCC(多版本并发控制)或锁机制来保证

一致性

一致性指事务执行前后,数据库会从一个符合业务规则的 “合法状态”,转换到另一个同样符合业务规则的 “合法状态”(小编提醒:这里的 “合法” 是指数据满足业务逻辑约束,比如 “转账前后总资金守恒”“库存扣减后不能为负数”。并不是说事务执行前后数据完全相同,而是通过事务保障操作后的数据依然 “逻辑正确”)。

实现原理:一致性是事务追求的最终目标,由原子性、隔离性和持久性共同保障,同时依赖业务逻辑的正确设计(如代码中对数据合法性的校验)

并发事务出现的问题

MySQL允许多个客户端同时连接。所以,当多个事务同时处理,就会产生脏读、不可重复读、幻读等并发事务问题

脏读

一个事务读取到了另一个事务尚未提交的修改数据。因为它还没有提交事务有可能发生回滚或者执行失败,那就还是原数据,但是事务却读取了修改但未提交的数据

不可重复读

在一个事务内,多次读取同一数据集合时,同一行数据的内容发生了变化,通常是因为其他事务对该行数据进行了更新。导致第一次读取的数据和第二次读取的数据不一样

幻读

在一个事务内,多次读取同一个数据集合时,数据的行数发生了变化。一般是由于其他事务执行了插入或删除操作,导致结果集的记录数量改变

丢失修改

第一个事务修改数据后,第二个事务也修改了这个数据。导致第一个事务内的修改结果被丢失(也就是第二个事务修改的数据将第一个事务修改的数据覆盖了)

假设你的银行账户初始余额是 1000 元,现在有两个事务(可以理解为两个 “操作流程”)同时要修改你的余额:

事务 1 先修改了数据(把余额改成 1500),但事务 2 并不知道事务 1 做了修改(它读取的还是初始的 1000),最后事务 2 把余额改成 1300,导致事务 1 的修改结果被 “覆盖” 了(相当于白加了 500)。

为了解决以上这些问题,标准SQL定义了4类事务隔离级别

事务隔离级别

读未提交(READ UNCOMITTED,RU)

事务可读取其他未提交事务的修改,导致脏读、不可重复读、幻读

读已提交(READ COMMITTED,RC)

事务只能读取其他已提交事务的修改,可避免脏读,但仍可能出现不可重复读、幻读

可重复读(REPEATABLE READ,RR)

MySQL InnoDB默认隔离级别。事务正在读取数据,不允许其他事物进行修改操作,事务期间多次读取同一数据结果一致,可避免脏读、不可重复读,通过Next-Key Lock机制避免幻读

串行化(SERIALIZABLE)

当多个事务对同一条数据进行读写操作时,通过加锁的方式,强制事务串行执行。可避免所有并发问题,但并发性能极差

本节篇章的核心目标,是帮大家对 MySQL 事务建立初步认知:无论是解决数据混乱的 ACID 特性、实操性强的事务语法,还是并发场景下的脏读、幻读等问题,以及对应的隔离级别方案,都是咱们理解事务的基础。

需要特别注意的是,事务隔离级别的实现离不开‘锁机制’的支撑 —— 这也是理解 MySQL 并发控制的关键。下一篇章,小编就聚焦 MySQL 锁机制,带大家深入看看它是如何保障事务隔离性的~

MySQL内容丰富感谢大家耐心观看🐱

有问题欢迎留言!!!😗

肥嘟嘟左卫门就讲到这里啦,记得一键三连!!!😗

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值