正确使用php mysqli的autocommit和rollback

4

您在使用mysqli autocommit时遇到了问题。以下是相关查询。

Table1和Table3是InnoDB,而Table2是MyISAM

成功插入了Table2和Table3的数据,但是无法存储数据到Table1中。 在运行代码时没有出现任何错误。

$dbconnect->autocommit(false);

$stmt = $dbconnect->prepare("INSERT INTO `table1`(`col1`,`col2`) VALUES (?,?)");
$stmt->bind_param('ss',$val1,$val2);
$stmt->execute();
$dbconnect->rollback();

$stmt = $dbconnect->prepare("INSERT INTO `table2`(`col1`,`col2`) VALUES (?,?)");
$stmt->bind_param('ss',$val3,$val4);
$stmt->execute();
$dbconnect->rollback();

$stmt = $dbconnect->prepare("INSERT INTO `table3`(`col1`,`col2`) VALUES (?,?)");
$stmt->bind_param('ss',$val5,$val6);
$stmt->execute();

$dbconnect->commit();

何时以及如何使用autocommit(false)和rollback()呢?


使用autocommit(false)可以在执行多个SQL语句时将它们作为一个事务来处理,直到使用commit()将更改保存到数据库。而如果需要回滚之前对数据库所做的所有更改,则可以使用rollback()函数。
1个回答

9

当您有一系列必须一起执行以维护数据库一致性的SQL语句时,您可以使用它。将调用提交视为在游戏中建立保存点。每次调用回滚都会撤消到上一个提交所做的所有操作。

想象一种情况,您需要在发票表中保存发票,在发票详细信息表中保存详细信息,并在付款表中保存付款记录。为了保持一致性,您需要确保这些全部完成或全部不完成。如果您先添加发票和详细信息,然后插入付款时发生故障,则数据库处于不一致状态。

通常使用try/catch块来实现此目的,如下所示:

try {
    $dbconnect->autocommit(false);

    $stmt = $dbconnect->prepare("INSERT INTO `invoices`(`col1`,`col2`) VALUES (?,?)");
    $stmt->bind_param('ss',$val1,$val2);
    $stmt->execute();

    $stmt = $dbconnect->prepare("INSERT INTO `invoice_details`(`col1`,`col2`) VALUES (?,?)");
    $stmt->bind_param('ss',$val3,$val4);
    $stmt->execute();

    $stmt = $dbconnect->prepare("INSERT INTO `payments`(`col1`,`col2`) VALUES (?,?)");
    $stmt->bind_param('ss',$val5,$val6);
    $stmt->execute();

    $dbconnect->commit();
} catch(Exception $e){
    // undo everything that was done in the try block in the case of a failure.
    $dbconnect->rollback();

    // throw another exception to inform the caller that the insert group failed.
    throw new StorageException("I couldn't save the invoice");
}

1
现在我明白了。所以commit用于提交事务,而rollback用于回滚事务。那么truefalse的自动提交参数呢?手册上说“是否打开自动提交”。那么将其设置为false就是关闭自动提交吗? - Jo E.
1
这是正确的。可能最好的解决方案是让它保持开启,只有在需要时才关闭。此外,使用 transaction 可能是有意义的,这样您就不必担心自动提交设置的值。 - Orangepill
正如我在 PHP 文档中所读到的评论,打开和关闭自动提交也会提交尚未提交的所有内容。那么我可以只是再次打开它而不是提交吗?在 try 结束时使用 $dbconnect->autocommit(true) - Lithilion
可能不是最好的想法。由于该行为未记录在文档中,因此可能会在未来的版本中发生更改。 - Orangepill
那么先 commit 然后再打开 autocommit(true) 更好吗? - Lithilion
假设在 catch 块之后,您的脚本已经完成并且连接正在关闭。在这种情况下,回滚调用是不必要的,因为没有调用提交?或者挂起的更改会在关闭时被提交吗? - Mazen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接