Недавно я наткнулся на код, к которому какое-то время не прикасался, но хотел его запустить. И это не удалось, хотя я почти уверен, что раньше это работало. Итак, я исследовал, и выяснилось: именно обработка транзакций изменилась с PHP 7.x на 8.x с autocommit=0. Я искал журнал изменений PHP, но не нашел никаких указаний. Я надеялся, что кто-нибудь сможет прояснить мой разум, потому что после некоторого расследования я, возможно, тоже неправильно понял, как это должно работать.
К проблеме: в PHP 8.x, когда я вызываю PDO: :beginTransaction() выдает ошибку, если до этого произошли какие-либо запросы, предположительно потому, что предыдущие запросы автоматически открывали транзакцию (сообщение: «Уже есть активная транзакция»). До PHP 8 работал тот же код, как мне показалось после тестирования, что PDO::beginTransaction() зафиксировал бы любую открытую транзакцию. Я прикрепил код внизу, который воспроизводит это поведение.
- Первый вопрос будет о режиме автофиксации. Документация по этому вопросу довольно скудна, а также не найдено ничего об изменениях в журналах изменений PHP 8. Есть идеи, где можно найти дополнительную информацию?
- Почему мои выборки требуют (и автоматически открывают) транзакцию? Все равно откатывать нечего. Это особенно болезненно, если вы не хотите использовать autocommit для неявного управления записью в вашем коде, но любая библиотека или тип, который запрашивает базу данных, вызывает сбои. Вот как это должно работать? Можем ли мы каким-то образом сделать выборку транзакционной самостоятельно, не влияя на запись?
- Я понимаю, что PHP 7.x, вероятно, имел ошибочное поведение. У меня сложилось впечатление, что он просто автоматически фиксирует любые выборки, но похоже, что это влияет и на запись. Итак, метод BeginTransaction() автоматически фиксирует транзакцию, даже если автофиксация отключена.
- Могу ли я как-то предотвратить автоматическое открытие транзакций? На данный момент ошибка возникает только тогда, когда я правильно открываю транзакцию, но у меня нет никакой информации о том, где мог произойти запрос, который открыл транзакцию.
$pdo = new PDO(...);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND, 'SET NAMES \'UTF8\', autocommit=0');
$pdo->setAttribute(PDO::ATTR_AUTOCOMMIT, false);
$sql = 'SELECT id FROM test WHERE id = 1';
$stmt = $pdo->prepare($sql);
$stmt->execute();
$pdo->beginTransaction();
try {
$stmt = $pdo->prepare('INSERT INTO test(`id`, `value`) VALUES(2, "Test")');
$stmt->execute();
$stmt = $pdo->prepare('INSERT INTO test(`value`) VALUES("Missing ID")');
$stmt->execute();
$pdo->commit();
} catch (Exception $e) {
$pdo->rollback();
echo "ROLLBACK:". $e->getMessage();
}
Подробнее здесь: https://stackoverflow.com/questions/790 ... o-in-php-8