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

Теперь вы знаете, как подключаться к базам данных посредством 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();
}
?>

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

Коментарии

Typically data definition language clauses (DDL) will trigger the database engine to automatically commit:
http://dev.mysql.com/doc/refman/5.0/en/implicit-commit.html

Many other databases (e.g. Oracle) will implicitly commit before and after running DDL statements.
2012-10-26 22:25:23
http://php5.kiev.ua/manual/ru/pdo.transactions.html
Some DBMSs allow DDL (table creation/alteration) within transactions, some do not. Asking "Does my DBMS allow DDL within transactions without forcing a commit?" gives the following example answers:

CUBRID: Yes
DB2 UDB: Yes
Firebird: Yes
Informix: Yes
MySQL: No
Oracle: No (although schema upgrades can be rolled out using "edition-based redefinition")
PostgreSQL: Yes
SQLite: Yes
SQL Server: Sometimes, depending on isolation level, type of command, etc.
Sybase: Yes
2017-12-18 05:11:54
http://php5.kiev.ua/manual/ru/pdo.transactions.html
> You're not limited to making updates in a transaction; you can also issue complex 
> queries to extract data, and possibly use that information to build up more updates 
> and queries; while the transaction is active, you are guaranteed that no one else can 
> make changes while you are in the middle of your work. For further reading on 
> transactions, refer to the documentation provided by your database server. 

This only holds true if you specifically do "SELECT .... FOR UPDATE". 

Without the "FOR UPDATE" part, when two transactions run at the same time, the second transaction could change a value AFTER the first transaction read it, but BEFORE the first transaction used it for updates.

Without the "FOR UPDATE" part you are absolutely NOT GUARANTEED that no one else can make changes while you are in the middle of your work.
2022-07-05 11:08:32
http://php5.kiev.ua/manual/ru/pdo.transactions.html

    Поддержать сайт на родительском проекте КГБ