首页 > 解决方案 > MySQL 如何正确使用事务?

问题描述

我在我的项目中遇到了实现交易的需要——这是我以前从未做过的事情。我已经检查了我的 aytocommit 是否设置为 1 - 我不确定我是否需要触摸它?

现在我有一组脚本,它们都包含首先连接到数据库的函数。有一个完美的放置mysqli_begin_transaction($link);, 和的地方mysqli_autocommit($link, FALSE);,所以无论特定脚本是否需要它,我都会在任何地方进行事务,并关闭自动提交 - 如果那里很差,则 php.net 上的文档但我应该这样做。所以我的问题不是。1 & 2 将是:无论脚本是否需要它,都可以在任何地方开始事务吗?我也应该像这样禁用自动提交吗?

现在假设我有这样的脚本(很抱歉没有提供实际代码,但我的问题是关于事务如何工作,而不是关于代码本身):

~insert and/or update things
~do something aka "line 2"
~insert and/or update things again 

似乎是直接从书中采取的例子。我显然希望所有插入和更新,或者没有发生。由于我已经开始交易,我假设,除非我调用mysqli_commit ($link);. 但是在这里我们有一个小问题:我没有在我的脚本末尾包含任何“页脚”,现在这样做似乎是一场噩梦,所以我没有任何地方可以提交。所以问号。3 是:即使我将 autocommit 设置为 false,我的查询是否会在脚本结束(或者我调用exit;or )后自动提交?die();还是我需要调用提交/不关闭自动提交?

现在是时候处理某些事情失败并且我需要回滚的情况了。与上述相同 -我是否需要调用mysqli_rollback (mysqli $link);,或者我没有调用 commit 的纯粹事实就足够了?我在这里指的是脚本没有正常结束的情况。诸如在“第 2 行”上工作时关闭服务器电源的情况,或者因为花费了太多时间而停止(set_time_limit停止它)。

标签: mysqltransactions

解决方案


这是一个有点宽泛的问题,所以我会尽量涵盖所有内容。

一开始你可以忽略 mysqli api(api 特定的事务函数只是包装器),直接看MySQL 手册。这里重要的是禁用自动提交和启动事务是一回事。此外,单个查询(包括触发器的修改)始终是一个事务。

您问题 1 和 2 的答案是“可能不是”。这在很大程度上取决于您现有代码对数据库连接的假设,以及您的应用程序的结构。

从您在问题中提到的内容来看,答案是:如果您只将交易放在需要它们的地方会更好。

对于问题 3:它不会自动提交。但是,您可以通过使用register_shutdown_function来做到这一点,尽管我不建议这样做。

有一些语句(隐式提交)会自动提交事务。这些包括所有 DDL 语句(CREATE、ALTER...)以及 TRUCNATE、LOCK TABLES 等。这基本上意味着这些语句不能在事务中使用。

MySQL 在连接终止时回滚事务。

我建议仅将事务添加到需要它们的代码中(为了安全起见,您可以对所有对数据库执行多个写入查询的代码执行此操作)。

经典的做法是:

START TRANSACTION
query
other things
another query
some other stuff
3-rd query
...
COMMIT

这里的主要内容是确保您仅在没有发生错误的情况下提交。

将回滚留给连接终止(或者register_shutdown_function如果您正在使用持久连接),因为确保每个脚本都具有正确工作的回滚逻辑是困难的:)

这将确保如果发生坏事(异常、致命错误、时间/内存限制、停电、流星......),不会发生任何事情。

也可以在函数/方法级别(嵌套和类似堆栈)进行事务,但这超出了这个问题的范围。


推荐阅读