问题
I have two queries both dependent on each other, i.e. if first query is not executed the second shouldn't be executed, and the other way around if second can't be executed the first shouldn't be executed.
INSERT INTO `table` VALUES (1,2,3)
UPDATE `otherTable` SET `val1`=1 WHERE `id`=$idOfInsert
ON DUPLICATE KEY UPDATE
is not the answer.
I tried using mysqli::multi_query
but as it turned out it executes the first even though the second can't be executed (it stops on error).
How can I achieve this in PHP?
回答1:
You can use transactions, if the engine you use support it (InnoDB, BDB).
See http://dev.mysql.com/doc/refman/5.0/en/commit.html for examples.
Edit: quick example using 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
You may want to optimize the queries (i.e. not execute the second one if the first has failed, use prepared statements, ...)
回答2:
What I was looking for are transactions. @tmuguet's answer has really helped me back then, but now looking at it from the perspective of time I would like to provide a more up to date answer.
Each query needs to be executed separately and using prepared statements to prevent SQL injection.
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;
}
Of course for this to work properly you need to have mysqli error reporting enabled. Just add this line before new mysqli()
in your code.
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
回答3:
Use [INSERT IGNORE] to make the SQL server ignore the errors.
INSERT IGNORE INTO `table` VALUES (1,2,3);
Then use LAST_INSERT_ID() to get the inserted ID or 0 if nothing was inserted. This will make UPDATE fail if since there is no record with an ID = 0.
UPDATE `otherTable` SET `val1`=1 WHERE `id`=LAST_INSERT_ID();
回答4:
Break it into multiple query calls:
$result = mysql_query("INSERT ...");
if ($result) {
mysql_query("UPDATE ...");
}
But the "don't do first if second can't" is impossible. PHP cannot reach back in time and warn the first query that the second one has failed.
来源:https://stackoverflow.com/questions/14175813/multiple-queries-dependent-on-each-other