【问题标题】:Multiple queries dependent on each other多个相互依赖的查询
【发布时间】:2013-01-05 20:00:43
【问题描述】:

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

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

ON DUPLICATE KEY UPDATE 不是答案。

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

如何在 PHP 中实现这一点?

【问题讨论】:

  • "如果第二个不能执行,第一个不应该执行" 这个要求是对逻辑的直接挑战。不可能
  • @HankyPanky 数据库事务专门用于处理这些情况,以保证一致性。
  • 根据起始状态,你想要的完成状态是什么?你说的不是很清楚。 PS 更新命令/语句不是查询。

标签: php mysql sql mysqli


【解决方案1】:

如果您使用的引擎支持(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

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

【讨论】:

  • 添加了赞成票,因为事务不仅是使查询依赖的一个很好的选择,而且它们还能够防止在事务等期间断开连接时数据丢失(这就是为什么它被称为事务哈哈)
  • THIS 关心我吗?
  • 如果你没有使用 mysqlnd_ms,没有。看来您使用 mysqli,绝对没有。
  • 还有一件事:为什么不用&= 而不是|=
  • 因为您希望事务在查询之一失败 (OR) 时停止。但显然,如果您有更多查询,这不是管理事务的好方法。
【解决方案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);

【讨论】:

    【解决方案3】:

    使用 [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();
    

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

      • mysql_query() 自 5.5 起已弃用,您需要 mysqli_query()。
      • "PHP 无法及时回溯".. 其实 PHP 的 mysqli / mysql 函数支持事务。事务检查所有查询是否正常运行。如果其中一个失败,它将“撤消”(回滚)查询
      猜你喜欢
      • 1970-01-01
      • 2015-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-03
      • 2020-12-14
      • 2021-08-31
      • 2011-04-26
      相关资源
      最近更新 更多