Ваш второй скрипт ожидает вставки second , а не первой вставки.
Если я проверю ваш код с помощью эхо-операторов:
//First script, i use pdo for connection
$pdo->beginTransaction();
echo "begin done\n";
$pdo->exec("INSERT INTO sample (unique_str) VALUES('first')");
echo "insert('first') done\n";
$pdo->exec("INSERT INTO sample (unique_str) VALUES('violate_str')");
echo "insert('violate_str') done\n";
sleep(50); //I'll start second script here
echo "sleep done\n";
$pdo->commit();
echo "commit done\n";
//Second script
$pdo->beginTransaction();
echo "begin done\n";
$pdo->exec("INSERT INTO sample (unique_str) VALUES('third')");
echo "insert('third') done\n";
$pdo->exec("INSERT INTO sample (unique_str) VALUES('violate_str')");
echo "insert('violate_str') done\n";
$pdo->commit();
echo "commit done\n";
Я вижу вывод из первого скрипта:
begin done
insert('first') done
insert('violate_str') done
Теперь он перешел в спящий режим, поэтому я запускаю второй скрипт и сразу же вижу вывод:
begin done
insert('third') done
На данный момент он ждет. Итак, мы знаем, что он завершил одну вставку без ожидания. Он ожидает второй вставки, которая находится в конфликте со вставкой 'violate_str'. Это связано с тем, что первый сценарий уже создал эту запись в уникальном индексе, хотя и не зафиксировал ее. Он по-прежнему удерживает блокировку этого значения в индексе, поэтому второй сценарий должен ожидать эту блокировку.
Как только сон заканчивается, первый скрипт фиксируется и выдает:
sleep done
commit done
Затем второй скрипт может получить блокировку и попытаться вставить строку. Но, к сожалению, первый скрипт уже вставил это значение и зафиксировал его, поэтому мы получаем нарушение ключа-дубликата.
Fatal error: Uncaught PDOException: SQLSTATE[23000]: Integrity constraint violation:
1062 Duplicate entry 'violate_str' for key 'unique_str'
Если первый сценарий должен был сделать rollback()
вместо commit()
, тогда он снимает блокировку и отменяет вставку. Это позволяет второй сценарий, чтобы закончить и вставить спорное значение свободно.