MySQL之事务

前言

 事务是一个或多个 SQL 语句组成的一个执行单元,这些 SQL 语句要么全部执行成功,要么全部不执行,不会出现部分执行的情况。事务是数据库管理系统执行过程中的一个逻辑单位,由一个有限的数据库操作序列构成。
 事务的主要作用是保证数据库操作的一致性,即事务内的操作,要么全部成功,要么全部失败回滚,不会出现中间状态。这对于维护数据库的完整性和一致性非常重要。


一、事务的四大特性

 事务具有四个基本特性,也就是通常所说的 ACID 特性,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。

  • 原子性:事务的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务中的操作不能只执行其中一部分。
  • 一致性:事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致性与业务规则有关,比如银行转账,不论事务成功还是失败,转账双方的总金额应该是不变的。
  • 隔离性:多个并发事务之间需要相互隔离,即一个事务的执行不能被其他事务干扰。
  • 持久性:一旦事务提交,则其所做的修改将永久保存到数据库中。即使发生系统崩溃,修改的数据也不会丢失

在这里插入图片描述

二、如何保证事务的四大特性?

MySQL 通过事务、undo log、redo log 来确保 ACID。

2.1 如何保证原子性?

MySQL 通过 undo log 来确保原子性(Atomicity)。
 当事务开始时,MySQL 会在undo log中记录事务开始前的旧值。如果事务执行失败,MySQL 会使用undo log中的旧值来回滚事务开始前的状态;如果事务执行成功,MySQL 会在某个时间节点将undo log删除。

2.2 如何保证一致性?

如果其他三个特性都得到了保证,那么一致性(Consistency)就自然而然得到保证了。

2.3 如何保证隔离性?

MySQL 定义了多种隔离级别,通过 MVCC 来确保每个事务都有专属自己的数据版本,从而实现隔离性(Isolation)。
 在 MVCC 中,每行记录都有一个版本号,当事务尝试读取记录时,会根据事务的隔离级别和记录的版本号来决定是否可以读取。

2.4 如何保证持久性?

redo log 是一种物理日志,当执行写操作时,MySQL 会先将更改记录到 redo log 中。当 redo log 填满时,MySQL 再将这些更改写入数据文件中。
 如果 MySQL 在写入数据文件时发生崩溃,可以通过 redo log 来恢复数据文件,从而确保持久性(Durability)

三、事务的隔离级别有哪些?MySQL的默认隔离级别是什么?

 事务的隔离级别定了一个事务可能受其他事务影响的程度,MySQL 支持的四种隔离级别分别是:读未提交(Read Uncommitted)、读已提交(Read Committed)、可重复读(Repeatable Read)和串行化(Serializable)

  1. 读未提交是最低的隔离级别,在这个级别,当前事务可以读取未被其他事务提交的数据,以至于会出现“脏读”、“不可重复读”和“幻读”的问题;
  2. 读已提交 当前事务只能读取已经被其他事务提交的数据,可以避免“脏读”现象。但不可重复读和幻读问题仍然存在。
  3. 可重复读 确保在同一事务中多次读取相同记录的结果是一致的,即使其他事务对这条记录进行了修改,也不会影响到当前事务(可重复读是 MySQL 默认的隔离级别,避免了“脏读”和“不可重复读”,但可能会出现幻读)
  4. 串行化 最高的隔离级别,通过强制事务串行执行来避免并发问题,可以解决“脏读”、“不可重复读”和“幻读”问题(但会导致大量的超时和锁竞争问题)

四、什么是脏读、不可重复读、幻读呢?

4.1 脏读

脏读指的是一个事务能够读取另一个事务尚未提交的数据。如果读到的数据在之后被回滚了,那么第一个事务读取到的就是无效的数据。

-- 事务 A
START TRANSACTION;
UPDATE employees SET salary = 5000 WHERE id = 1;

-- 事务 B
START TRANSACTION;
SELECT salary FROM employees WHERE id = 1;  -- 读取到 salary = 5000 (脏读)
ROLLBACK;

4.2 不可重复读

不可重复读指的是在同一事务中执行相同的查询时,返回的结果集不同。这是由于在事务过程中,另一个事务修改了数据并提交。比如说事务 A 在第一次读取某个值后,事务 B 修改了这个值并提交,事务 A 再次读取时,发现值已经改变。

-- 事务 A
START TRANSACTION;
SELECT salary FROM employees WHERE id = 1;  -- 读取到 salary = 3000

-- 事务 B
START TRANSACTION;
UPDATE employees SET salary = 5000 WHERE id = 1;
COMMIT;

-- 事务 A 再次读取
SELECT salary FROM employees WHERE id = 1;  -- 读取到 salary = 5000 (不可重复读)
COMMIT;

4.3 幻读

幻读指的是在同一事务中执行相同的查询时,返回的结果集中出现了之前没有的数据行。这是因为在事务过程中,另一个事务插入了新的数据并提交。
比如说事务 A 在第一次查询某个条件范围的数据行后,事务 B 插入了一条新数据且符合条件范围,事务 A 再次查询时,发现多了一条数据。

-- 事务 A
START TRANSACTION;
SELECT * FROM employees WHERE department = 'HR';  -- 读取到 10 条记录

-- 事务 B
START TRANSACTION;
INSERT INTO employees (id, name, department) VALUES (11, 'John Doe', 'HR');
COMMIT;

-- 事务 A 再次查询
SELECT * FROM employees WHERE department = 'HR';  -- 读取到 11 条记录 (幻读)
COMMIT;

4.4不同的隔离级别,在并发事务下可能会发生什么问题?

在这里插入图片描述

五、事务的各个隔离级别都是如何实现的?

5.1 读未提交是如何实现的?

不提供任何锁机制来保护读取的数据,允许读取未提交的数据(即脏读)

5.2 读已提交和可重复读通过 MVCC 机制中的 ReadView 来实现。

  1. READ COMMITTED:每次读取数据前都生成一个 ReadView,保证每次读操作都是最新的数据。
  2. REPEATABLE READ:只在第一次读操作时生成一个 ReadView,后续读操作都使用这个 ReadView,保证事务内读取的数据是一致的。

5.3串行化是如何实现的?

事务在读操作时,必须先加表级共享锁,直到事务结束才释放;事务在写操作时,必须先加表级排他锁,直到事务结束才释放。

  • 15
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值