Я пытаюсь настроить свою первую транзакцию в MySQL с помощью PHP / PDO …
У меня есть быстрый вопрос: какой лучший способ определить, был ли предыдущий запрос успешным или нет? Вот что я имею прямо сейчас, но я бы скорее нашел способ протестировать запрос с помощью оператора if.
Это в значительной степени макет кода, чтобы попытаться получить рабочую модель. Я знаю, что $ results не эффективно тестирует, если что-то хорошее или плохое. У меня есть там больше как место для реальной сделки, когда придет время ..
if ($_POST['groupID'] && is_numeric($_POST['groupID'])) { $sql = "SET AUTOCOMMIT=0"; $dbs = $dbo->prepare($sql); $dbs->execute(); $sql = "START TRANSACTION"; $dbs = $dbo->prepare($sql); $dbs->execute(); $sql = "DELETE FROM users_priveleges WHERE GroupID=:groupID"; $dbs = $dbo->prepare($sql); $dbs->bindParam(":groupID", $_POST['groupID'], PDO::PARAM_INT); $dbs->execute(); try { $sql = "DELETE FROM groups WHERE GroupID=:groupID LIMIT 1"; $dbs = $dbo->prepare($sql); $dbs->bindParam(":groupID", $_POST['groupID'], PDO::PARAM_INT); $dbs->execute(); $results["error"] = null; $results["success"] = true; try { $sql = "DELETE FROM users WHERE Group=:groupID"; $dbs = $dbo->prepare($sql); $dbs->bindParam(":groupID", $_POST['groupID'], PDO::PARAM_INT); $dbs->execute(); $results["error"] = null; $results["success"] = true; $sql = "COMMIT"; $dbs = $dbo->prepare($sql); $dbs->execute(); } catch (PDOException $e) { $sql = "ROLLBACK"; $dbs = $dbo->prepare($sql); $dbs->execute(); $results["error"] = "Could not delete associated users! $e"; $results["success"] = false; } } catch (PDOException $e) { $sql = "ROLLBACK"; $dbs = $dbo->prepare($sql); $dbs->execute(); $results["error"] = "COULD NOT REMOVE GROUP! $e"; $results["success"] = false; } }
Некоторые общие замечания: Не используйте bindParam()
если вы не используете процедуру, которая изменяет значение параметра. Поэтому use bindValue()
. bindParam () принимает значение аргумента как ссылочную переменную. Это означает, что вы не можете сделать $stmt->bindParam(':num', 1, PDO::PARAM_INT);
– он вызывает ошибку. Кроме того, PDO имеет свои собственные функции для управления транзакциями, вам не нужно выполнять запросы вручную.
Я немного переписал ваш код, чтобы пролить свет на то, как можно использовать PDO:
if($_POST['groupID'] && is_numeric($_POST['groupID'])) { // List the SQL strings that you want to use $sql['privileges'] = "DELETE FROM users_priveleges WHERE GroupID=:groupID"; $sql['groups'] = "DELETE FROM groups WHERE GroupID=:groupID"; // You don't need LIMIT 1, GroupID should be unique (primary) so it's controlled by the DB $sql['users'] = "DELETE FROM users WHERE Group=:groupID"; // Start the transaction. PDO turns autocommit mode off depending on the driver, you don't need to implicitly say you want it off $pdo->beginTransaction(); try { // Prepare the statements foreach($sql as $stmt_name => &$sql_command) { $stmt[$stmt_name] = $pdo->prepare($sql_command); } // Delete the privileges $stmt['privileges']->bindValue(':groupID', $_POST['groupID'], PDO::PARAM_INT); $stmt['privileges']->execute(); // Delete the group $stmt['groups']->bindValue(":groupID", $_POST['groupID'], PDO::PARAM_INT); $stmt['groups']->execute(); // Delete the user $stmt['users']->bindParam(":groupID", $_POST['groupID'], PDO::PARAM_INT); $stmt['users']->execute(); $pdo->commit(); } catch(PDOException $e) { $pdo->rollBack(); // Report errors } }
Я не буду готовить и выполнять транзакционные заявления. Я бы использовал PDO :: beginTransaction () , PDO :: commit () и PDO :: rollback () .
PDO :: prepare () и PDO :: execute () возвращают FALSE, если есть ошибка, иначе они генерируют исключение PDOException, если вы устанавливаете атрибут (PDO :: ATTR_ERRMODE, PDO :: ERRMODE_EXCEPTION) .
В обработчике исключений вы должны проверить PDO :: errorInfo () и сообщить о характере ошибки. Лучшей практикой является регистрация исходной информации об ошибке, но дать пользователю более дружественное сообщение.
Не повторяйте буквальное сообщение об ошибке в пользовательском интерфейсе – это может дать пользователю неправильное знание вашего SQL-запроса и схемы.
Выполнение PDO Statement execute()
возвращает TRUE при успешном завершении и FALSE при сбое, поэтому вы можете проверить возвращаемое значение предыдущего execute()
в инструкции if.
$pdo_result = $dbs->execute(); if ($pdo_result) { // handle success } else { // handle failure // you can get error info with $dbs->errorInfo(); }
Тем не менее, как правильно указывает @Bill Kerwin (в его ответе, что я полностью выдвигаюсь, потому что это точно правильно), было бы предпочтительнее использовать PDO::beginTransaction()
, PDO::commit()
и PDO::rollback()
.