Вопрос или проблема
Должен ли я вызывать beginTransaction / Commit для каждого prepare->(“”) выражения? Или только один раз для всего кода?
Я пишу довольно объемный код таким образом, но беспокоюсь, что, когда я закончу, всё будет некорректно. Как мне правильно поступить?
Пример:
self::$pdo->beginTransaction();
$cmd = self::$pdo->prepare("
INSERT INTO historico_horas (id_data, id_colab, atrasos, data_ocorrencia, data_registro) VALUES (:iddata, :id, :qnt_atrasos, :dataocorrencia, :dataregistro)");
$id_data_gerado = self::$pdo->lastInsertId();
$cmd->bindParam(":iddata", $id_data_gerado);
$cmd->bindParam(':id', self::$ColabId);
$cmd->bindParam(':qnt_atrasos', $totalMinutos);
$cmd->bindParam(':dataocorrencia', $d_ocorr);
$cmd->bindParam(':dataregistro', self::$dataRegistro);
if ($cmd->execute()) {
if ($_ENV['APP_ENV'] == "development") {
self::$logger->info('Данные успешно зафиксированы в базе данных.');
}
self::$pdo->commit();
Alert::Alert("AtrasoCad");
exit();
} else {
if ($_ENV['APP_ENV'] == "development") {
self::$logger->info('Не удалось зафиксировать данные в истории.');
}
self::$pdo->rollBack();
}
exit();
Ответ или решение
Вопрос о том, как правильно использовать транзакции в PDO (PHP Data Objects), имеет важное значение, особенно когда вам необходимо выполнять несколько операций вставки или обновления с целью поддержания целостности данных. Давайте подробно рассмотрим использование методов beginTransaction()
, commit()
, и rollback()
.
Правильное использование транзакций
-
Транзакция на уровне блока операций: Вам не следует вызывать
beginTransaction()
иcommit()
для каждой отдельной операции илиprepare()
; вместо этого следует использовать их на уровне логического блока операций. Это означает, что вы начинаете транзакцию сbeginTransaction()
, выполняете несколько операций, и затем, если все прошло успешно, вызываетеcommit()
, а в случае ошибки —rollback()
. Это позволяет группе связанных изменений быть атомарными, т.е. все изменения будут согласованными или не будут применены вовсе. - Ваш пример: В вашем коде вы используете транзакцию правильно, но есть некоторые моменты, которые можно улучшить. Например, если у вас несколько запросов, вы хотите, чтобы все они выполнялись в рамках одной транзакции.
Пример многократных операций
self::$pdo->beginTransaction();
try {
$cmd1 = self::$pdo->prepare("
INSERT INTO historico_horas (id_data, id_colab, atrasos, data_ocorrencia, data_registro)
VALUES (:iddata, :id, :qnt_atrasos, :dataocorrencia, :dataregistro)");
// Привязка параметров
$cmd1->bindParam(":iddata", $id_data_gerado);
$cmd1->bindParam(':id', self::$ColabId);
$cmd1->bindParam(':qnt_atrasos', $totalMinutos);
$cmd1->bindParam(':dataocorrencia', $d_ocorr);
$cmd1->bindParam(':dataregistro', self::$dataRegistro);
// Выполнение первого запроса
if (!$cmd1->execute()) {
throw new Exception('Ошибка при выполнении первого запроса');
}
// Дополнительные операции могут быть выполнены здесь
// Например, другой запрос:
$cmd2 = self::$pdo->prepare("INSERT INTO другая_таблица (столбец1, столбец2) VALUES (:значение1, :значение2)");
// Привязка и выполнение cmd2...
// Если все прошло успешно
self::$pdo->commit();
} catch (Exception $e) {
// Если что-то пошло не так, откатим изменения
self::$pdo->rollBack();
if ($_ENV['APP_ENV'] == "development") {
self::$logger->error('Транзакция откатана: ' . $e->getMessage());
}
}
Заключение
- В одном блоке: Всегда используйте одну транзакцию на логический блок операций, а не для каждого запроса отдельно.
- Исключения: Обрабатывайте исключения корректно, чтобы обеспечить откат в случае ошибок.
- Логирование: Используйте логирование для отслеживания действий и ошибок, это поможет в отладке и мониторинге.
Следование этим рекомендациям поможет вам эффективно управлять транзакциями в вашем приложении и гарантировать целостность данных.