PDO
PHP Manual

Транзакции и автоматическая фиксация изменений

Теперь вы знаете, как подключаться к базам данных посредством PDO. Но перед тем как выполнять запросы, вам необходимо понять, как PDO управляет транзакциями. Если вы прежде не сталкивались с транзакциями, они обладают четырьмя главными свойствами, это Атомарность, Согласованность, Изолированность и Долговечность (ACID). Говоря простым языком, любые действия, совершенные в рамках транзакции, гарантированно будут выполнены безопасно для базы данных, и на них не повлияют другие подключения к этой базе, даже если эти действия совершаются в несколько этапов. Транзакционные операции можно отменять по запросу (если транзакция еще не зафиксирована), что упрощает обработку ошибок в скрипте.

Механизм транзакций реализован путем "временного сохранения" всех изменений и дальнейшего применения этих изменений, как единого целого. Это позволяет добиться резкого увеличения эффективности подобных изменений. Другими словами, транзакции могут сделать ваш скрипт более быстрым и потенциально более стабильным (но для этого необходимо корректно использовать этот механизм).

К сожалению, не все базы данных поддерживают транзакции, поэтому PDO при создании подключения работает в режиме так называемой "автоматической фиксации". Режим автофиксации означает, что каждый запрос к базе данных, который вы выполняете, неявно заключается в транзакцию, если СУБД их поддерживает. Если база данных не поддерживает этот механизм, запрос обрабатывается без транзакции. Чтобы явно обозначить начало транзакции, вы должны использовать метод PDO::beginTransaction(). Однако, в этом случае, если драйвер не поддерживает механизм транзакций, будет выброшено исключение PDOException (вне зависимости от выбранного способа обработки ошибок: подобные ситуации - это всегда серьезная недоработка). Будучи внутри границ транзакции, ее можно зафиксировать методом PDO::commit() или откатить методом PDO::rollBack(), в зависимости от того, успешно выполнен ваш код внутри транзакции или нет.

Внимание

PDO проверяет возможность использования транзакций только на уровне драйвера. Если по каким-то причинам механизм транзакций недоступен, но сервер баз данных принял запрос на открытие транзакции, PDO::beginTransaction() вернет TRUE без ошибок.

В качестве примера можно попробовать использовать транзакции для изменения MyISAM таблиц базы данных MySQL.

При завершении работы скрипта или при закрытии соединения, PDO автоматически откатывает все незавершенные транзакции. Это делается, чтобы предотвратить нарушения целостности базы данных в случаях, когда скрипт неожиданно прерывает работу. Если вы явно не зафиксировали изменения, предполагается, что что-то пошло не так. Поэтому откат изменений - наиболее безопасный выход из ситуации.

Внимание

Изменения будут откачены автоматически, только если транзакция открыта методом PDO::beginTransaction(). Если транзакцию открыть вручную в тексте запроса, PDO об этом никак не узнает, и, соответственно, не сможет принять мер, если произойдет что-то плохое.

Пример #1 Выполнение пакета изменений в рамках транзакции

В следующем примере предположим, что мы создаем несколько записей для нового сотрудника с номером ID 23. Помимо ввода основной информации необходимо записать его зарплату. Довольно просто сделать два отдельных обновления таблиц, однако путем заключения этих запросов в рамки PDO::beginTransaction() и PDO::commit() мы сможем гарантировать, что никто не увидит этих изменений, пока все они не завершатся. Если что-то пойдет не так, catch-блок откатит все изменения с начала транзакции и напечатает сообщение об ошибке.

<?php
try {
  
$dbh = new PDO('odbc:SAMPLE''db2inst1''ibmdb2'
      array(
PDO::ATTR_PERSISTENT => true));
  echo 
"Подключились\n";
} catch (
Exception $e) {
  die(
"Не удалось подключиться: " $e->getMessage());
}

try {  
  
$dbh->setAttribute(PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION);

  
$dbh->beginTransaction();
  
$dbh->exec("insert into staff (id, first, last) values (23, 'Joe', 'Bloggs')");
  
$dbh->exec("insert into salarychange (id, amount, changedate) 
      values (23, 50000, NOW())"
);
  
$dbh->commit();
  
} catch (
Exception $e) {
  
$dbh->rollBack();
  echo 
"Ошибка: " $e->getMessage();
}
?>

Вы никак не ограничены в количестве запросов в рамках транзакции; вы также можете выполнять сложные запросы, чтобы извлечь данные, а затем использовать их для создания других запросов на обновление и извлечение данных; если транзакция активна, вы можете быть уверены, что никто не сможет изменить ваши данные, пока вы с ними работаете. За дополнительной информацией о транзакциях обращайтесь к документации к вашему серверу баз данных.


PDO
PHP Manual