【问题标题】:MySQL How to properly use transactions?MySQL 如何正确使用事务?
【发布时间】:2019-01-31 08:29:49
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

    标签: mysql transactions


    【解决方案1】:

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

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

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

    从你在问题中提到的情况来看,答案是:如果你只把交易放在需要它们的地方会更好。

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

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

    当连接终止时,MySQL 会回滚事务。

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

    经典的做法是:

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

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

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

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

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

    【讨论】:

    • 非常感谢您提供如此详细的回答!只是为了确保:如果我在确实需要它的脚本的开头使用START TRANSACTION,并在它的结尾使用COMMIT,它只会在脚本到达提交点时提交,我不必完全使用回滚,不用担心超时和流星?第二件事:如果我同时使用die(); - 它会回滚吗,未完成的事务将在某处“挂起”,如果用户刷新脚本直到提交 - 这个未完成的事务会提交吗?
    • 它只会在提交点提交。回滚取决于您是否使用持久连接。如果你不是 - 它会在脚本退出时回滚(断开连接)。如果你是 - 除非你回滚,否则事务将“挂在某处”(我为此使用register_shutdown_function,并且在连接后立即回滚以防万一)。
    • 如果我想要一种运行 SQL 语句的故障安全方式,我是否使用 START TRANSACTION 和 ROLLBACK 如果它运行成功,将 ROLLBACK 替换为 COMMIT 并重新运行查询?另外,我可以在 TRANSACTION/COMMIT 之间有一个 ALTER 语句吗?谢谢。
    • 回滚并运行两次相同的东西是没有意义的。如果出现某种错误,请不要提交。您不能在事务中进行 ALTER、CREATE、TRUNCATE、DROP 等。当您运行 ALTER(或任何其他 DDL)时,事务将被提交。此限制不适用于临时表。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-25
    • 2013-01-19
    • 1970-01-01
    • 2013-07-20
    • 2017-07-17
    • 2012-04-26
    • 2016-03-17
    相关资源
    最近更新 更多