2

我有两个相互依赖的查询,即如果第一个查询未执行,则不应执行第二个查询,反之,如果无法执行第二个查询,则不应执行第一个查询。

INSERT INTO `table` VALUES (1,2,3)
UPDATE `otherTable` SET `val1`=1 WHERE `id`=$idOfInsert

ON DUPLICATE KEY UPDATE不是答案。

我尝试使用mysqli::multi_query,但事实证明它会执行第一个,即使第二个无法执行(它会因错误而停止)。

我怎样才能在 PHP 中实现这一点?

4

4 回答 4

4

如果您使用的引擎支持它(InnoDB、BDB),您可以使用事务。

有关示例,请参见http://dev.mysql.com/doc/refman/5.0/en/commit.html

编辑:使用mysqli的快速示例:

$connection->autocommit(FALSE); // disable auto-commit and start a new transaction
$result  = $connection->query("INSERT INTO `table` VALUES (1,2,3)");
$result &= $connection->query("UPDATE `otherTable` SET `val1`=1 WHERE `id`=$idOfInsert");
if (!$result) {
  // One of the queries has failed: cancel the transaction
  $connection->rollback();
} else {
  // Both queries worked:commit the current transaction
  $connection->commit();
}
$connection->autocommit(TRUE); // enable auto-commit

您可能想要优化查询(即,如果第一个查询失败,则不执行第二个查询,使用准备好的语句,...)

于 2013-01-05T20:09:16.013 回答
2

我正在寻找的是交易。@tmuguet 的回答当时确实帮助了我,但现在从时间的角度来看,我想提供一个更新的答案。

每个查询都需要单独执行并使用准备好的语句来防止 SQL 注入。

try {
    // Start transaction
    $mysqli->begin_transaction();

    $mysqli->query('INSERT INTO `table` VALUES (1,2,3)');

    $stmt = $mysqli->prepare('UPDATE otherTable SET val1=1 WHERE id=?');
    $stmt->bind_param('s', $idOfInsert);
    $stmt->execute();

    // Commit changes
    $mysqli->commit();
} catch (\Throwable $e) {
    // Something went wrong. Rollback
    $mysqli->rollback();
    throw $e;
}

当然,要使其正常工作,您需要启用 mysqli 错误报告。只需new mysqli()在您的代码中添加此行。

mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
于 2020-03-01T15:12:22.630 回答
-1

使用 [INSERT IGNORE] 使 SQL 服务器忽略错误。

INSERT IGNORE INTO `table` VALUES (1,2,3);

然后使用 LAST_INSERT_ID() 获取插入的 ID,如果没有插入任何内容,则使用 0。如果没有 ID = 0 的记录,这将使 UPDATE 失败。

UPDATE `otherTable` SET `val1`=1 WHERE `id`=LAST_INSERT_ID();
于 2013-01-05T20:17:14.920 回答
-3

将其分解为多个查询调用:

$result = mysql_query("INSERT ...");
if ($result) {
    mysql_query("UPDATE ...");
}

但是“第二个不行就不要做”是不可能的。PHP 无法及时返回并警告第一个查询第二个查询失败。

于 2013-01-05T20:03:17.200 回答