Я использую PHP с таблицами PDO и InnoDB.
Я хочу, чтобы код позволял завершать только одну отправленную пользователем операцию, пользователь может отменить или завершить. Но в случае, когда пользователь публикует обе операции, я хочу, чтобы один из запросов завершился с ошибкой и откат, чего сейчас не происходит, обе завершаются без исключения / ошибка. Я думал, что удаления строки после проверки ее существования будет достаточно.
$pdo = new PDO();
try {
$pdo->beginTransaction();
$rowCheck = $pdo->query("SELECT * FROM table WHERE id=99")->rowCount();
if ($rowCheck == 0)
throw new RuntimeException("Row isn't there");
$pdo->exec("DELETE FROM table WHERE id = 99");
// either cancel, which does one bunch of queries. if (isset($_POST['cancel'])) ...
// or complete, which does another bunch of queries. if (isset($_POST['complete'])) ...
// do a bunch of queries on other tables here...
$pdo->commit();
} catch (Exception $e) {
$pdo->rollback();
throw $e;
}
Как я могу сделать отмену / завершение операций критическим разделом? Вторая операция ДОЛЖНА завершиться неудачей.
Код в порядке, за одним исключением: Добавить FOR UPDATE
к первоначальному SELECT
, Этого должно быть достаточно, чтобы заблокировать нажатие второй кнопки до первого DELETE
произошло, что привело ко второму «провал».
https://dev.mysql.com/doc/refman/5.5/en/innodb-locking-reads.html
Примечание Блокировка строк для обновления с помощью
SELECT FOR UPDATE
применяется только
когда автокоммит отключен (либо путем начала транзакции с
START TRANSACTION
или установив autocommit на 0. Если autocommit имеет значение
включено, строки, соответствующие спецификации, не блокируются.
Другое решение только для полноты:
private function getLock() {
$lock = $this->pdo->query("SELECT GET_LOCK('my_lock_name', 5)")->fetchColumn();
if ($lock != "1")
throw new RuntimeException("Lock was not gained: " . $lock);
}
private function releaseLock() {
$releaseLock = $this->pdo->query("SELECT RELEASE_LOCK('my_lock_name')")->fetchColumn();
if ($releaseLock != "1")
throw new RuntimeException("Lock not properly released " . $releaseLock);
}