Если у меня есть несколько запросов по цепочке, по структуре, основанной на IF, например:
$query1 = mysqli_query("query here");
if(!query1){
//display error
} else {
$query2 = mysqli_query("another query here");
if(!query2){
//display error
//rollback the query1
} else {
query3 = mysqli_query("yet again another query");
if(!query3) {
//display error
//rollback the query2
//rollback the query1
} else {
query4 = mysqli_query("eh.. another one");
if(!query4){
//display error
//rollback the query3
//rollback the query2
//rollback the query1
} else {
return success;
}
}
}
}
Есть ли лучший способ откатить предыдущий запрос, если следующий не удастся?
В противном случае я получу первые два запроса успешно, которые отредактировали базу данных, но 3 ° не удалось, поэтому 3 ° и 4 ° не отредактировали dabatase, в результате чего он был поврежден.
Я думал о чем-то вроде:
...
$query2 = mysqli_query("another query here");
if(!query2){
//display error
$rollback = mysqli_query("query to rollback query1");
} else {
query3 = mysqli_query("yet again another query");
if(!query3) {
//display error
$rollback = mysqli_query("query to rollback query2");
$rollback = mysqli_query("query to rollback query1");
} else {
...
Но вышеупомянутый метод дает еще больше шансов на провал большего количества запросов.
Есть ли другие более эффективные методы?
Вот как бы я сделал это с mysqli
:
Сконфигурируйте mysqli (где-то в начале вашего приложения) для выдачи исключений при сбое запроса.
mysqli_report(MYSQLI_REPORT_STRICT);
Таким образом, вам не нужно будет все if .. elseif .. else
,
$connection->begin_transaction();
try {
$result1 = $connection->query("query 1");
// do something with $result1
$result2 = $connection->query("query 2");
// do something with $result2
$result3 = $connection->query("query 3");
// do something with $result3
// you will not get here if any of the queries fails
$connection->commit();
} catch (Exception $e) {
// if any of the queries fails, the following code will be executed
$connection->rollback(); // roll back everything to the point of begin_transaction()
// do other stuff to handle the error
}
Обновить
Обычно пользователю все равно, почему его действие не удалось. Если запрос терпит неудачу, это никогда не ошибка пользователя. Это либо вина разработчика, либо окружающей среды. Поэтому не должно быть причин для вывода сообщения об ошибке в зависимости от того, какой запрос не удался.
Обратите внимание, что если intput пользователя является источником неудачного запроса, то
Однако — я не говорю, что не может быть причин — я просто не знаю никаких. Поэтому, если вы хотите, чтобы ваше сообщение об ошибке зависело от того, какой запрос не удался, вы можете сделать следующее:
$error = null;
$connection->begin_transaction();
try {
try {
$result1 = $connection->query("query 1");
} catch (Exception $e) {
$error = 'query 1 failed';
throw $e;
}
// do something with $result1
try {
$result2 = $connection->query("query 2");
} catch (Exception $e) {
$error = 'query 2 failed';
throw $e;
}
// do something with $result2
// execute more queries the same way
$connection->commit();
} catch (Exception $e) {
$connection->rollback();
// use $error to find out which query failed
// do other stuff to handle the error
}
Других решений пока нет …