MySQL 事务

2025年3月17日 | 阅读 7 分钟

MySQL 中的事务是一系列语句、查询或操作(如 select、insert、update 或 delete)作为一个单一工作单元执行,可以提交或回滚。如果事务对数据库进行了多次修改,会发生以下两件事:

  • 要么在事务提交时所有修改都成功。
  • 要么在事务回滚时所有修改都被撤销。

换句话说,一个事务必须完成集合中的每一个操作才能算成功。这意味着如果任何一个语句失败,事务操作都无法产生结果。

MySQL 中的事务从第一个可执行的 SQL 语句开始,并在遇到显式或隐式的 COMMIT 或 ROLLBACK 时结束。显式使用 COMMIT 或 ROLLBACK 语句,隐式则在使用 DDL 语句时。

让我们通过以下解释来理解事务的概念。

我们可以通过考虑一个银行数据库来理解 MySQL 中事务的概念。假设一位银行客户想将资金从一个账户转到另一个账户。我们可以通过使用将分为以下几个步骤的 SQL 语句来实现:

  • 首先,需要检查第一个账户中是否有足够的可用余额。
  • 接下来,如果金额可用,则从中扣除。然后,更新第一个账户。
  • 最后,将金额存入第二个账户。然后更新第二个账户以完成事务。
  • 如果上述任何过程失败,事务将被回滚到其之前的状态。

事务的属性

事务主要包含四个属性,通常称为ACID属性。现在,我们将详细讨论 ACID 属性。ACID 属性代表:

  1. 原子性
  2. 一致性
  3. 隔离
  4. 耐用性

原子性 (Atomicity):此属性确保事务单元中的所有语句或操作都必须成功执行。否则,如果任何操作失败,整个事务将中止,并回滚到其之前的状态。它包含以下功能:

  • COMMIT 语句。
  • ROLLBACK 语句。
  • 自动提交设置。
  • 来自 INFORMATION_SCHEMA 表的操作数据。

一致性 (Consistency):此属性确保数据库仅在事务成功提交后才更改状态。它还负责保护数据免受崩溃。它包含以下功能:

  • InnoDB 双写缓冲区。
  • InnoDB 崩溃恢复。

隔离性 (Isolation):此属性保证事务单元中的每个操作都独立运行。它还确保语句之间是透明的。它包含以下功能:

  • SET ISOLATION LEVEL 语句。
  • 自动提交设置。
  • InnoDB 锁的低级细节。

持久性 (Durability):此属性保证已提交事务的结果会永久保存,即使系统崩溃或失败。它包含以下功能:

  • 存储设备中的写缓存。
  • 存储设备中的电池备用缓存。
  • 配置选项 innodb_file_per_table。
  • 配置选项 innodb_flush_log_at_trx_commit。
  • 配置选项 sync_binlog。

MySQL 事务语句

MySQL 使用以下语句来控制事务:

  • MySQL 提供 START TRANSACTION 语句来开始事务。它还提供 "BEGIN" 和 "BEGIN WORK" 作为 START TRANSACTION 的别名。
  • 我们将使用 COMMIT 语句来提交当前事务。它允许数据库永久更改。
  • 我们将使用 ROLLBACK 语句来回滚当前事务。它允许数据库取消所有更改并恢复到其之前的状态。
  • 我们将使用 SET auto-commit 语句来禁用/启用当前事务的自动提交模式。默认情况下, COMMIT 语句会自动执行。因此,如果我们不想自动提交更改,请使用以下语句:

再次,使用以下语句启用自动提交模式:

MySQL 事务示例

假设我们有两个名为 "employees""Orders" 的表,其中包含以下数据:

表:employees

MySQL Transaction

表:orders

MySQL Transaction

COMMIT 示例

如果我们想使用事务,则需要将 SQL 语句分解为逻辑部分。之后,我们可以决定是提交还是回滚数据。

以下步骤说明了如何创建事务:

  1. 使用 START TRANSACTION 语句开始事务。
  2. 然后,选择员工中的最高收入。
  3. 向 employee 表添加新记录。
  4. 向 order 表添加新记录。
  5. 使用 COMMIT 语句完成事务。

以下是执行上述操作的命令:

下图更清晰地说明了这一点:

MySQL Transaction

ROLLBACK 示例

我们可以通过以下说明来理解回滚事务。首先,打开 MySQL 命令行提示符并使用密码登录到数据库服务器。接下来,我们需要选择一个数据库。

假设我们的数据库包含 "Orders" 表。现在,以下是执行回滚操作的脚本:

执行上述语句后,我们将得到如下输出,显示 Orders 表中的所有记录都已成功删除。

MySQL Transaction

现在,我们需要打开一个单独的 MySQL 数据库服务器会话,并执行以下语句来验证 Orders 表中的数据:

这将产生如下输出:

MySQL Transaction

尽管我们在第一个会话中进行了更改,但我们仍然可以看到表中存在记录。这是因为在第一个会话中执行 COMMIT 或 ROLLBACK 语句之前,更改并非永久性的。

因此,如果我们想使更改永久化,请使用 COMMIT 语句。否则,请执行 ROLLBACK 语句以回滚第一个会话中的更改。

成功执行后,将产生以下结果,我们可以看到更改已被回滚。

MySQL Transaction

在 MySQL 事务中无法回滚的语句。

MySQL 事务无法回滚所有语句。例如,这些语句包括 DDL(数据定义语言)命令,如 CREATE、ALTER 或 DROP 数据库,以及 CREATE、UPDATE 或 DROP 表或存储例程。我们在设计事务时必须确保不包含这些语句。

SAVEPOINT、ROLLBACK TO SAVEPOINT、RELEASE SAVEPOINT

SAVEPOINT 语句在事务内部创建一个带有标识符名称的特殊标记。它允许回滚在 savepoint 之后执行的所有语句。因此,事务将恢复到它在 savepoint 时所处的状态。如果我们为当前事务设置了多个同名 savepoint,则新的 savepoint 负责回滚。

ROLLBACK TO SAVEPOINT 语句允许我们在不中止事务的情况下回滚到已建立的给定 savepoint 的所有事务。

RELEASE SAVEPOINT 语句会销毁当前事务中的命名 savepoint,而不会撤消在建立 savepoint 后执行的查询所产生的影响。在此之后,不再发生回滚命令。如果 savepoint 不存在于事务中,则会报错。

以下是 MySQL 事务中上述语句的语法

示例

让我们通过示例来理解如何使用这些语句。在下面的示例中,我们将使用 SAVEPOINT 和 ROLLBACK TO SAVEPOINT 语句,它们解释了 savepoint 如何确定当前事务中哪些记录可以被回滚。

在上面:

  • 我们必须首先开始事务,然后显示 Orders 表中可用的记录。
  • 接下来,我们在表中插入一条记录,然后创建一个 savepoint 标记。
  • 我们再次在表中插入一条记录,然后使用 ROLLBACK TO SAVEPOINT 语句删除在 savepoint 建立处所做的更改。
  • 我们再次在表中插入一条记录。
  • 最后,执行 COMMIT 语句以永久保存更改。

下面的输出按顺序解释了上述步骤,这有助于非常容易地理解它。

MySQL Transaction

现在,我们将使用 SELECT 语句来验证上述操作。在输出中,我们可以看到 order_id=6order_id=8 已成功添加,但 order_id=7 未插入表中。它回滚了在建立 savepoint 后输入的值。

MySQL Transaction

现在我们将使用另一个示例 RELEASE SAVEPOINT,它建立 my_savepoint 然后删除一个 savepoint。

在输出中,我们可以看到事务中的所有语句都已成功执行。在这里,INSERT 和 UPDATE 语句都在 COMMIT 时修改了表。

MySQL Transaction
下一主题MySQL 分区