Подтвердить что ты не робот

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

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

Если вы никогда не сталкивались с транзакциями раньше, они предлагают 4 основных Особенности: Атомность, Консистенция, Изоляция и Долговечность (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() происходит

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

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

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

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

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

Значит

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

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

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

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

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

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

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

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

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

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

Ответ 3

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

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

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

(Примечание: это не "тупик", просто "ожидание".)