当前位置: 首页 > article >正文

MySQL中的事务(如果想知道MYSQL中有关事务的知识,那么只看这一篇就足够了!)

        前言:事务管理是数据库确保数据一致性和可靠性的核心机制,通过将一组操作作为一个整体执行,事务要么完全成功,要么完全失败,避免了数据不一致的问题,在多用户并发环境中,事务隔离级别决定了不同事务的交互方式,影响系统的性能和一致性。


✨✨✨这里是秋刀鱼不做梦的BLOG

✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客

在正式开始讲解之前,先让我们看一下本文大致的讲解内容:

目录

1.事务的初识

        (1)事务的概念

        (2)事务的基本操作

        (3)事务的回滚与保存点

2.ACID 特性

        (1)原子性(Atomicity)

        (2)一致性(Consistency)

        (3)隔离性(Isolation)

        (4)持久性(Durability)

3.事务隔离级别

        (1)读未提交

        (2)读已提交

        (3)可重复读

        (4)串行化(SERIALIZABLE)

4.自动提交与手动提交模式

        (1)自动提交模式 

        (2)手动提交模式


1.事务的初识

        (1)事务的概念

        在开始学习MySQL中的事务之前,先让我们来了解一下什么是MySQL中的事务:

事务是将一组 SQL 操作封装为一个整体,确保这些操作要么全都成功,要么全都失败

        事务的主要应用场景大致有资金转账、库存扣减等多个步骤组成的操作,保证这些操作能够在出现错误时进行回滚,从而确保数据的一致性和完整性。

        通过上述的简短描述,我们就对MySQL中事务的定义有了初步的了解了,那么接下来让我们进一步了解一下MySQL中的事务。

        (2)事务的基本操作

        在 MySQL 中,事务的控制是通过以下 SQL 语句来实现的:

  • START TRANSACTIONBEGIN:开启事务。
  • COMMIT:提交事务,将所有更改持久化保存。
  • ROLLBACK:回滚事务,撤销对数据的所有修改。

        例如,考虑一个简单的银行转账操作,假设要从账户 A 扣款 100 元,往账户 B 存款 100 元。我们希望这两个操作要么都成功,要么都失败,若出现任何问题,都应当回滚整个事务。

START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;  -- 扣款操作
UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;  -- 存款操作
COMMIT;  -- 提交事务,保存所有更改

代码解释:

        首先启动一个事务,然后执行两条 SQL 语句:从账户 A 扣款 100 元,同时往账户 B 存款 100 元,最后,通过 COMMIT 提交事务,确保这两个操作成功保存。

        通过上述的案例,我们就大致的了解了MySQL中的事务的基本操作了!!!

        (3)事务的回滚与保存点

        回滚是事务中的一个重要特性,如果在事务执行过程中遇到错误,可以通过 ROLLBACK 将所有更改撤销,恢复到事务开始之前的状态,除此之外,MySQL 还支持使用 保存点 来标记事务中的特定位置,允许在出现错误时仅回滚到某个特定的保存点,而不是完全回滚。

START TRANSACTION;
SAVEPOINT savepoint1;  -- 设置保存点
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;  
-- 如果发生错误,回滚到保存点
ROLLBACK TO SAVEPOINT savepoint1;
COMMIT;  -- 提交事务

代码解释:

        保存点 savepoint1 被设置在事务开始后,若发生错误,事务会回滚到此保存点,避免撤销整个事务的所有操作。

        至此,我们就大致的初识了MySQL中的事务的内容了!!!

2.ACID 特性

        在学习完了MySQL中的事务的基本概念之后,在让我们学习一下ACID 特性,ACID 是数据库事务的核心概念,它代表了四个基本的属性:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability),这四个特性确保了事务的正确性和数据库的稳定性。

        (1)原子性(Atomicity)

        原子性意味着事务中的所有操作要么全部执行成功,要么全部执行失败,如果事务中的任何操作失败,整个事务会被回滚,恢复到事务开始之前的状态。

例子:

        ——假设我们正在进行一个资金转账操作,如果扣款成功但是存款失败,整个事务应该回滚,确保资金不会丢失,以下是实现原子性的代码:

START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;  -- 扣款操作
UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;  -- 存款操作
-- 如果第二个操作失败,整个事务回滚
ROLLBACK;  -- 恢复到事务开始之前的状态

代码解释:

        如果存款操作由于某些原因失败,那么事务会回滚到开始时的状态,确保数据不会处于不一致的状态。

        (2)一致性(Consistency)

        一致性意味着事务必须确保数据库的完整性约束得到遵守,事务执行前后,数据库从一个一致的状态过渡到另一个一致的状态,无论事务是否成功完成,数据库都应该处于有效的状态。

例子:

        ——在银行转账中,必须保证在扣款和存款操作之间,账户余额的变化始终遵循一定的规则,例如,账户余额不能为负数。

START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
-- 确保账户余额大于零
IF (SELECT balance FROM accounts WHERE account_id = 1) < 0 THEN
    ROLLBACK;  -- 如果余额不足,回滚事务
END IF;
UPDATE accounts SET balance = balance + 100 WHERE account_id = 2;
COMMIT;

代码解释:

        在进行扣款操作后,我们检查账户余额是否足够,如果余额不足,则回滚事务,否则继续执行存款操作,这样可以确保数据库的一致性。

        (3)隔离性(Isolation)

        隔离性保证了事务的执行不受其他事务的干扰,即使多个事务同时执行,它们的操作互不影响,为了实现隔离性,数据库管理系统提供了不同的事务隔离级别,每个隔离级别在并发性能与数据一致性之间做了不同的权衡。

MySQL 支持四种事务隔离级别:

  1. READ UNCOMMITTED(读未提交):事务可以读取其他事务未提交的数据,可能会发生脏读。
  2. READ COMMITTED(读已提交):事务只能读取已提交的数据,避免脏读,但仍然可能发生不可重复读。
  3. REPEATABLE READ(可重复读):事务中的所有查询都能读取到一致的数据,避免了不可重复读。
  4. SERIALIZABLE(串行化):事务按照顺序执行,确保没有并发问题,但性能最低。

例子:

        ——在 MySQL 中,我们可以设置事务的隔离级别,以下代码展示了如何设置事务的隔离级别:

-- 查看当前事务隔离级别
SELECT @@global.tx_isolation;
-- 设置事务隔离级别为 REPEATABLE READ
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT balance FROM accounts WHERE account_id = 1;  -- 读取账户余额
COMMIT;

代码解释:

        我们设置了事务的隔离级别为 REPEATABLE READ,这意味着事务执行过程中,所有的读取操作将看到相同的数据,从而避免了不可重复读的问题。

        (4)持久性(Durability)

        持久性确保了事务一旦提交,对数据的修改将永久写入数据库,即使系统发生崩溃或其他故障,数据也不会丢失。

例子:

START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
COMMIT;  -- 提交事务,修改会被永久保存

代码解释:

        即使在提交后,系统崩溃了,数据库仍然会从日志文件中恢复到一致状态,确保资金的变动不会丢失。

        这样我们就学习完了MySQL中的.ACID 特性了!!!

3.事务隔离级别

        接下来在让我们学习一下事务隔离级别,我们知道,MySQL 使用 InnoDB 存储引擎支持四种事务隔离级别,分别为:READ UNCOMMITTED(读未提交)、READ COMMITTED(读已提交)、REPEATABLE READ(可重复读)和 SERIALIZABLE(串行化),这些隔离级别通过锁机制和多版本并发控制(MVCC)来实现,不同的隔离级别会影响数据的一致性和并发性能。

        (1)读未提交

        读未提交是最低的隔离级别,事务 A 可以读取事务 B 中尚未提交的数据,由于事务 A 读取的数据可能是一个未提交的更改,因此会导致所谓的 脏读(Dirty Read)。

  • 脏读:事务 A 在事务 B 提交前读取了事务 B 对某个数据的修改,如果事务 B 回滚,事务 A 读取到的数据就是无效的。
  • 优点:性能最优,适合对数据一致性要求不高的场景。
  • 缺点:可能导致数据不一致,极易引发逻辑错误。

例子:

        —— 假设有两个事务同时进行,一个事务正在更新数据,而另一个事务可以读取这个未提交的更新。

-- 事务 A
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;

-- 事务 B
START TRANSACTION;
SELECT balance FROM accounts WHERE account_id = 1;  -- 读取事务 A 未提交的数据
COMMIT;

代码解释:

        事务 B 读取到了事务 A 尚未提交的更改。如果事务 A 最终回滚,事务 B 读取的数据就是无效的,产生了脏读问题。

        (2)读已提交

        读已提交隔离级别解决了脏读问题,确保事务只能读取已提交的数据。但它仍然允许在同一个事务内多次查询返回不同结果,产生 不可重复读(Non-repeatable Read)问题。

  • 不可重复读:在同一个事务中多次读取同一数据,但每次读取的结果不同,因为其他事务可能已经提交了更改。
  • 优点:避免了脏读,保证了数据的一致性。
  • 缺点:容易产生不可重复读问题。

例子:

        ——在 READ COMMITTED 隔离级别下,事务 A 在同一事务内的两次查询结果可能不同。

-- 事务 A
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
SELECT balance FROM accounts WHERE account_id = 1;  -- 第一次查询

-- 事务 B
START TRANSACTION;
UPDATE accounts SET balance = balance - 50 WHERE account_id = 1;
COMMIT;  -- 事务 B 提交

-- 事务 A
SELECT balance FROM accounts WHERE account_id = 1;  -- 第二次查询,结果不同
COMMIT;

代码解释:

        事务 A 的第二次查询结果与第一次查询的结果不同,因为事务 B 在事务 A 的查询之间提交了更改。

        (3)可重复读

        可重复读隔离级别解决了不可重复读问题,确保在同一个事务中,所有的查询操作返回的结果始终一致。InnoDB 存储引擎使用多版本并发控制(MVCC)机制来实现这一点。

  • 可重复读:事务内的所有读取操作,始终返回相同的数据,即使其他事务修改了这些数据。
  • 幻读:在 REPEATABLE READ 隔离级别下,虽然事务 A 在多次读取中得到相同结果,但在查询过程中,另一个事务可以插入新的记录,导致事务 A 查询的范围发生变化,这就是幻读问题。
  • 优点:解决了脏读和不可重复读问题。
  • 缺点:仍然可能发生幻读。

例子:

-- 事务 A
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
SELECT balance FROM accounts WHERE account_id = 1;  -- 第一次查询

-- 事务 B
START TRANSACTION;
INSERT INTO accounts (account_id, balance) VALUES (3, 100);  -- 事务 B 插入新记录
COMMIT;

-- 事务 A
SELECT balance FROM accounts WHERE account_id = 1;  -- 第二次查询,可能出现幻读问题
COMMIT;

代码解释:

        虽然事务 A 中的查询结果始终一致,但如果事务 B 在事务 A 执行过程中插入了新的记录,事务 A 可能会遇到幻读问题,即查询的结果集发生了变化。

        (4)串行化(SERIALIZABLE)

        串行化是最严格的事务隔离级别,所有事务串行执行,互不干扰。它通过强制加锁的方式,确保一个事务在执行时,其他事务必须等待直到该事务完成,这种方式完全解决了所有的并发问题,包括脏读、不可重复读和幻读。

  • 优点:完全避免了脏读、不可重复读和幻读问题,确保数据的绝对一致性。
  • 缺点:性能最差,因为事务需要串行执行,严重影响并发性能。

例子:

-- 事务 A
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
SELECT balance FROM accounts WHERE account_id = 1;  -- 第一次查询

-- 事务 B
START TRANSACTION;
UPDATE accounts SET balance = balance - 50 WHERE account_id = 1;  -- 事务 B 更新数据
COMMIT;

-- 事务 A
SELECT balance FROM accounts WHERE account_id = 1;  -- 第二次查询,结果不会变化
COMMIT;

代码解释:

事务 A 和事务 B 会串行执行,事务 A 在执行期间会被阻塞,直到事务 B 完成。

        至此我们就了解了MySQL中的事务隔离级别了!!!

4.自动提交与手动提交模式

        最后在让我们学习一下自动提交与手动提交模式,在 MySQL 中,事务默认是自动提交的,这意味着每条 SQL 语句执行后都会立即提交,然而,有时开发者希望控制事务的提交过程,这时可以关闭自动提交,手动执行事务提交。

        (1)自动提交模式 

        ——默认情况下,MySQL 在每个 SQL 语句后都会自动提交事务,当然我们也可以设置自动提交事务:

-- 启用自动提交
SET AUTOCOMMIT = 1;

        (2)手动提交模式

        在手动提交模式下,事务不会自动提交,而是需要通过显式的 COMMITROLLBACK 来控制。

-- 禁用自动提交
SET AUTOCOMMIT = 0;
START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE account_id = 1;
-- 手动提交事务
COMMIT;

        通过手动提交事务,开发者可以更加精细地控制事务的执行,确保在复杂操作中的数据一致性。

        以上就是自动提交与手动提交模式的全部内容了!!!


以上就是本篇文章全部内容~~


http://www.kler.cn/a/500085.html

相关文章:

  • MATLAB语言的多线程编程
  • HTMLHTML5革命:构建现代网页的终极指南 - 0. 课程目录设计
  • python音乐播放器代码整理版
  • 大语言模型训练数据集格式
  • DeepSeek:性能强劲的开源模型
  • Redis集群模式下主从复制和哨兵模式
  • 深入学习 Python 爬虫:从基础到实战
  • git: hint:use --reapply-cherry-picks to include skipped commits
  • STM32如何使用内部晶振作为晶振
  • Spring Framework 5.3.x源码构建 (jdk-1.8, gradle 7.5.1, idea2024.3)
  • 【UE5 C++课程系列笔记】27——多线程基础——ControlFlow插件的基本使用
  • docker 部署Nginx UI
  • 在UE5中使用视差贴图
  • 线程并发下的单例模式
  • 20_Spring Boot默认缓存管理
  • 【机器学习:七、分类问题】
  • 微服务电商平台课程六:后端代码框架认识
  • CI/CD与自动化运维的结合:加速交付与稳定运维
  • 联想java开发面试题及参考答案
  • 73.矩阵置零 python
  • 代码随想录算法训练营第3天(链表1)| 203.移除链表元素 707.设计链表 206.反转链表
  • EJB与微服务:Java的秘密武器