Понимание транзакций pdo mysql

Документация PHP говорит:

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

ВОПРОС:

Означает ли это, что я могу иметь два отдельных сценария php, выполняющих транзакции одновременно, без их вмешательства друг в друга?


РАЗРАБОТКА НА ЧТО Я ЗНАЧИТЕЛЬНО « ИНТЕРФЕРЦИЮ » :

Представьте, что у нас есть следующая таблица employees :

  __________________________ | id | name | salary | |------+--------+----------| | 1 | ana | 10000 | |------+--------+----------| 

Если у меня есть два сценария с похожим / одинаковым кодом, они запускаются в одно и то же время:

script1.php и script2.php (оба имеют один и тот же код):

 $conn->beginTransaction(); $stmt = $conn->prepare("SELECT * FROM employees WHERE name = ?"); $stmt->execute(['ana']); $row = $stmt->fetch(PDO::FETCH_ASSOC); $salary = $row['salary']; $salary = $salary + 1000;//increasing salary $stmt = $conn->prepare("UPDATE employees SET salary = {$salary} WHERE name = ?"); $stmt->execute(['ana']); $conn->commit(); 

и предполагая, что последовательность событий такова:

  • script1.php выбирает данные

  • script2.php выбирает данные

  • Обновления данных script1.php

  • Обновления данных script2.php

  • script1.php commit () происходит

  • script2.php commit () происходит

Какова была бы заработная плата в этом случае?

  • Было бы 11000? И будет ли это тогда означать, что одна транзакция будет перекрываться с другой, потому что информация была получена до того, как произошла какая-либо фиксация?

  • Было бы 12000? И будет ли это тогда означать, что независимо от порядка, в котором данные были обновлены и выбраны, функция commit() заставила их произойти индивидуально?

Пожалуйста, не стесняйтесь разрабатывать столько, сколько хотите, о том, как транзакции и отдельные сценарии могут мешать (или не мешать) друг другу.

Вы не найдете ответа в php-документации, потому что это не имеет никакого отношения к php или pdo.

Индексный движок Innodb в mysql предлагает 4 так называемых уровня изоляции в соответствии со стандартом sql. Уровни изоляции в сочетании с блокирующими / неблокирующими чтениями будут определять результат приведенного выше примера. Вам нужно понять последствия различных уровней изоляции и выбрать подходящий для ваших нужд.

Подводя итог: если вы используете сериализованный уровень изоляции с отключенным автосохранением, тогда результат будет равен 12000. Во всех остальных уровнях изоляции и последовательном подключении с включенным автосохранением результат будет равен 11000. Если вы начнете использовать блокирующие чтения, тогда результат может быть 12000 при всех уровнях изоляции.

Судя по данным условиям (одиночный оператор DML), здесь вам не нужна транзакция, а блокировка таблицы. Это очень распространенная путаница.

Вам нужна транзакция, если вам нужно убедиться, что ВСЕ ваши инструкции DML были выполнены правильно или вообще не выполнялись.

Означает

  • вам не нужна транзакция для любого количества запросов SELECT
  • вам не нужна транзакция, если выполняется только один оператор DML

Хотя, как было отмечено в отличном ответе от Shadow, вы можете использовать транзакцию здесь с соответствующим уровнем изоляции, это было бы довольно запутанным. Здесь вам понадобится блокировка таблиц . Механизм InnoDB позволяет блокировать определенные строки вместо блокировки всей таблицы и, следовательно, должен быть предпочтительным.

Если вы хотите, чтобы зарплата составляла 1200, то используйте столовые замки.

Или – более простой способ – просто запустите запрос атомного обновления:

 UPDATE employees SET salary = salary + 1000 WHERE name = ? 

В этом случае все зарплаты будут записаны.

Если ваша цель другая, лучше выразьте ее явно.

Но опять же: вы должны понимать, что транзакции вообще не имеют никакого отношения к выполнению отдельных сценариев. Что касается вашей темы гонки, вас интересуют не транзакции, а блокировка таблицы / ряда. Это очень распространенная путаница, и вам лучше узнать ее прямо:

  • транзакция должна гарантировать, что набор запросов DML в одном скрипте был успешно выполнен.
  • блокировка таблицы / строки должна гарантировать, что другие действия сценария не будут мешать.

Единственная тема, где транзакции и блокировка помехи – это тупик , но опять же – это только в случае, когда транзакция использует блокировку.

Увы, «без помех» нуждается в некоторой помощи программиста. Для определения степени «транзакции» ему необходимо BEGIN и COMMIT . А также…

Ваш пример неадекватен. Для первого утверждения требуется SELECT ... FOR UPDATE . Это говорит о том, что обработка транзакций, вероятно, будет UPDATE для строк (строк), которые выбирает SELECT . Это предупреждение имеет решающее значение для «предотвращения помех». Теперь график времени:

  • script1.php НАЧИНАЕТСЯ
  • script2.php НАЧИНАЕТСЯ
  • script1.php выбирает данные ( FOR UPDATE )
  • script2.php выбирает данные, блокируется, поэтому он ждет
  • Обновления данных script1.php
  • script1.php commit () происходит
  • script2.php выбирает данные (и получает новое значение)
  • Обновления данных script2.php
  • script2.php commit () происходит

(Примечание. Это не «тупик», просто «ожидание».)