Статьи

Транзакции MySQL и почему их нельзя эмулировать в PHP

Моя недавняя статья «Топ-10 ошибок MySQL, сделанных разработчиками PHP» оказалась гораздо более противоречивой, чем я ожидал. Несколько из более интригующих ответов были от PHP-кодеров, которые считали транзакции ненужными накладными расходами. Они утверждают, что с качественным PHP-кодом вам не нужны транзакции или механизм хранения InnoDB MySQL.

Это правда, что вам не всегда нужны транзакции. Однако они полезны — и не только для банковских или финансовых приложений. Транзакция должна использоваться всякий раз, когда вам нужно обновить две или более записей и убедиться, что все они успешны.

Например, предположим, что мы создаем простую систему корзины покупок. После покупки требуется три обновления:

  1. добавить данные клиента в базу данных
  2. отметьте, что содержимое корзины было куплено
  3. соответственно уменьшить количество товаров на складе

В коде SQL это может разрешить:

INSERT INTO customers (name,email,cartid) VALUES ('Customer1','[email protected]',123);
UPDATE cart SET status='paid' WHERE id=123;
UPDATE product SET stock=stock-1 WHERE id=567;

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

Теперь я не буду сомневаться в качестве вашего PHP-кода. Вы можете запустить эти обновления SQL и проверить их успешность. Вы даже можете запросить существующие данные, чтобы в случае сбоя вернуться к исходной записи.

К сожалению, этого недостаточно. Ваш код может быть идеальным, но интерпретатор PHP, безусловно, не так. Также не работает веб-сервер. И не ОС, которую вы используете (да, даже Linux). MySQL также может исчезнуть. И давайте не будем забывать аппаратное обеспечение … процессоры умирают. Сбой жесткого диска. Память не работает. Серверы взрываются. ИТ-администраторы пинают сетевые кабели. Электрические сети отключены. Хостинговые компании обанкротились.

Проще говоря, вы никогда не можете быть уверены, что PHP-программа будет успешно работать и выполнять все команды SQL, как и ожидалось. Однако вы можете предотвратить загрязнение вашей базы данных в случае катастрофического сбоя.

Кислота — это лекарство

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

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

InnoDB или Бюст

Механизм хранения MyISAM по умолчанию MySQL не поддерживает транзакции, поэтому это не вариант. Если вы хотите использовать транзакции, убедитесь, что все ваши таблицы определены как InnoDB. Даже если вы не используете транзакции сейчас, вы никогда не знаете, как будет развиваться ваше приложение — если вы сомневаетесь, InnoDB — лучший выбор.

Использование транзакций

Несмотря на то, что они окутаны тайной, транзакции удивительно просты. Следующая инструкция SQL запускает транзакцию:

 START TRANSACTION;

В качестве альтернативы вы можете использовать:

 SET autocommit=0;

По умолчанию каждый оператор SQL выполняется в своей собственной транзакции. Отключение автоматической фиксации отменяет это действие, поэтому все последующие обновления SQL образуют часть одной транзакции.

примечание: альтернативные методы транзакций PHP

PHP предлагает несколько других альтернатив при запуске транзакции. Если вы используете библиотеку PDO, вы можете выполнить метод beginTransaction () . Для mysqli передайте false методу autocommit () .

Теперь, когда транзакция запущена, мы можем запустить любое количество SQL-запросов, вставок, обновлений и удалений. Ни одна из команд не будет постоянно влиять на базу данных, пока мы не убедимся, что это правильно. В этот момент мы запускаем:

 COMMIT;

Предполагая, что одна команда выполняется успешно, мы можем быть уверены, что наша база данных была обновлена. Библиотеки PHP PDO и mysqli также предоставляют методы commit()

Но что, если что-то пошло не так? Возможно, клиенту разрешили заказать товар, которого нет на складе? Вероятно, мы не хотим, чтобы наш уровень запасов был установлен на -1, поэтому мы можем отменить всю транзакцию и предупредить администратора.

Если мы не выполняем COMMIT, ни одно из обновлений данных не применяется, когда заканчивается страница PHP. Однако, так как мы все хорошие программисты, мы должны конкретно заявить, что хотим отменить транзакцию, используя:

 ROLLBACK;

Кроме того, библиотеки PHP PDO и mysqli предоставляют методы rollback()

Это транзакции в двух словах. Есть несколько уловов и исключений, но мы оставим их для моего следующего поста. А пока получайте удовольствие от транзакций ваших приложений!