transaction - php транзакции




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

Документация 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 ()

  • 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 в пределах одного сценария был успешно выполнен.
  • блокировка таблицы / строки должна гарантировать, что другие выполнения скрипта не будут мешать.

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





transactions