Я узнал, что предыдущие изменения postgres + PDO отменены, когда выбрано исключение (ДАЖЕ, КОГДА ИСКЛЮЧЕНИЕ ПРОДОЛЖАЕТСЯ И ПОРАЖЕНА!). Пример (в псевдокоде):
$transaction->begin(); try { $manager->insert("INSERT ..."); try { $manager->exec("A QUERY BREAKING SOME DB CONSTRAINT LIKE A UNIQUE INDEX ..."); } catch (\Exception $ex) { // IT IS CAUGHT AND SWALLOWED! } $transaction->commit(); } catch (Exception $ex) { $transaction->rollback(); // THIS CLEARLY DOES NOT RUN! }
В postgres первая вставка возвращается. В mysql нет.
Может ли кто-нибудь проливать свет на этот вопрос? Можно ли изменить это смехотворное поведение? Я хотел бы сам выполнить свои откаты и не получить pg, чтобы сделать это, когда он считает, что это уместно.
Это не ошибка PDO, она присуща управлению транзакциями PostgreSQL. Видеть:
PostgreSQL не откатывает транзакцию, но устанавливает ее в прерванное состояние, где она может только откатываться и где все операторы, кроме ROLLBACK
сообщают об ошибке:
ERROR: current transaction is aborted, commands ignored until end of transaction block
(Я удивлен, чтобы не найти это в официальной документации, думаю, мне нужно написать патч, чтобы улучшить это.)
Так. Когда вы пытаетесь / улавливаете и проглатываете исключение в PDO, вы захватываете исключение PHP-стороны, но вы не меняете того факта, что транзакция PostgreSQL находится в состоянии прервана.
Если вы хотите иметь возможность перехватывать исключения и продолжать использовать транзакцию, вы должны создать SAVEPOINT
перед каждым оператором, который может выйти из строя. Если он терпит неудачу, вы должны ROLLBACK TO SAVEPOINT ...;
, Если это удастся, вы можете RELEASE SAVEPOINT ...;
, Это накладывает дополнительные накладные расходы на базу данных для управления транзакциями, добавляет округлые поездки и быстрее сжигает идентификаторы транзакций (это означает, что PostgreSQL должен выполнять дополнительную работу по очистке фона).
Обычно предпочтительнее вместо этого создавать ваш SQL, чтобы он не подводил нормальные условия. Например, вы можете проверить большинство ограничений на стороне клиента, рассматривая ограничения на стороне сервера как второй уровень уверенности, удерживая большинство ошибок на стороне клиента.
Если это нецелесообразно, сделайте ваш отказ от приложения терпимым, чтобы он мог повторить неудачную транзакцию. Иногда это необходимо в любом случае – например, вы не можете вообще использовать точки сохранения для восстановления от сбоев транзакций или сбоев сериализации. Также может быть полезно, чтобы как можно более короткие транзакции, связанные с отказом, выполняли минимальную требуемую работу, поэтому вам нужно меньше отслеживать и повторять.
Итак: где это возможно, вместо проглатывания исключения, запускайте код базы данных, подверженный ошибкам, в цикле повтора. Убедитесь, что ваш код хранит запись информации, которая ему нужна, чтобы повторить всю транзакцию по ошибке, а не только последнее утверждение.
Помните, что любая транзакция может потерпеть неудачу: администратор баз данных может перезапустить базу данных для применения патча, система может закончиться из-за работы из-за беглого задания cron и т. Д. Таким образом, отказоустойчивые приложения – хороший дизайн.
Подкрепляет вас, по крайней мере, используя исключения PDO и исключения для обработки – вы уже опережаете большинство разработчиков.