php - attr_persistent - pdo-> begintransaction



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

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

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

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

Документация 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() вынуждала их происходить по отдельности?

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


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

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

Средства

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

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

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

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

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

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

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

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

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

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





transactions