Navicat 博客

在存储过程中使用事务来防止数据不一致 2021 年 4 月 20 日,由 Robert Gravelle 撰写

认识数据库事务文章中,我们探究了事务是如何通过保证使用事务执行的所有操作同时成功或同时失败来防止数据丢失和不一致。在今天的后续文章中,我们将学习如何在存储过程中使用事务,以确保所涉及的所有表保持一致状态。

关于 sp_delete_from_table 存储过程

如果你阅读过我以前的任何文章,你可能都知道我经常使用 Sakila 示例数据库来说明新概念。那么为何不使用它?它专门作为 MySQL 的学习数据库而开发。如果你尚未知道它是什么,我可以告诉你 Sakila 示例数据库包含与虚拟电影租赁商店链有关的数据。除了表和视图之外,你还可以找到用户函数、触发器、查询和存储过程,这些都是最常用的数据库对象和任务。

与本文相关的存储过程之一是 sp_delete_from_table。它接受以下三个输入参数:

  • @table:要从中删除行的表的名称。
  • @whereclause:用于标识要删除哪些行的条件。
  • @delcnt:我们希望删除多少行。

该过程返回 @actcnt(bigint)输出参数,它包含实际删除的行数。

以下是 Navicat Premium 中显示的完整定义:

delete_from_table_stored_proc (163K)

重要的事务语句

关系数据库为我们提供了一些重要的语句来控制交易:

  • 若要开始事务,请使用 BEGIN TRANSACTION 语句。BEGIN 或 BEGIN WORK 都是 BEGIN TRANSACTION 的别名。你可以在 sp_delete_from_table 过程的第 17 行找到它。
  • 若要提交当前事务并使它的更改永久生效,请使用 COMMIT 语句。这发生在过程的第 32 行。
  • 若要回滚当前事务并取消其更改,请使用 ROLLBACK 语句。在代码中有两种情况:
    1. 如果该语句将删除表中的所有行,则会显示一条消息,并在第 26 行回滚该事务。
    2. 如果删除的行数与预期的行数不匹配,则会再次显示一条消息,并回滚事务。这发生在第 38 行。
  • 若要禁用或启用当前事务的自动提交模式,请使用 SET autocommit 语句。默认情况下,某些数据库(例如 MySQL)在默认启用 autocommit 模式的情况下运行。这意味着,当不在事务内时,每个语句都是原子的,就像被 START TRANSACTION 和 COMMIT 围住一样。你不能使用 ROLLBACK 撤消语句的效果。但是,如果在语句运行期间发生错误,则会回滚该语句。由于大多数工作是在 sp_delete_from_table 过程中的事务内进行的,因此不需要 SET autocommit 语句。

测试事务回滚

由于我们知道如果预期计数与实际删除的行数不匹配,则 sp_delete_from_table 过程将会中止,因此可以通过确保 @whereclause 条件将删除表中的每一行或仅提供一个我们知道不匹配的 @delcnt 值来测试回滚。让我们尝试后者。

在 Navicat 中,我们可以通过“运行”按钮在编辑器运行存储过程。点击它会弹出一个接受输入参数的对话框(可以忽略输出参数):

input_dialog (23K)

过程终止后,可以在“信息”选项卡中看到输出信息。我们可以看到它已按预期回滚:

proc_result (33K)

总结

在今天的文章中,我们学习了如何在存储过程中使用事务,以确保无论结果如何,所涉及的所有表均保持一致状态。

如果你对 Navicat Premium 感兴趣,可以免费试用 14 天!




Rob Gravelle 居住在加拿大渥太华,是一名有 20 多年经验的 IT 专家。过往,Rob 曾为与情报有关的组织(如加拿大边境服务局和各种商业组织)构建系统。在业余时间,Rob 是一名出色的吉他演奏家,并发行了几张 CD

Navicat 文章
频道条目
分享
文章归档