Я видел много постов, объясняющих использование Select FOR UPDATE и как заблокировать строку, однако я не смог найти ни одного, объясняющего, что происходит, когда код пытается прочитать заблокированную строку.
Например. Скажем, я использую следующее:
$con->autocommit(FALSE);
$ps = $con->prepare( "SELECT 1 FROM event WHERE row_id = 100 FOR UPDATE");
$ps->execute();
...
//do something if lock successful
...
$mysqli->commit();
В этом случае, как определить, была ли моя блокировка успешной? Каков наилучший способ обработки сценария, когда строка уже заблокирована?
Извините, если это где-то описано, но все, что мне кажется, это объяснения «счастливого пути».
В этом случае, как определить, была ли моя блокировка успешной? Каков наилучший способ обработки сценария, когда строка уже заблокирована?
Если ряд вы пытаясь закрывать является уже заблокирован — сервер MySQL не будет возвращать никакого ответа для этой строки. Он будет ждать², пока транзакция блокировки не будет зафиксирована или откатана.
(Очевидно: если строка уже была удалена, ваш SELECT
вернет пустой набор результатов и ничего не заблокирует)
После этого он вернет последнее значение, зафиксированное транзакцией, которая удерживала блокировку.
регулярное Select
Заявления не будут заботиться о блокировке и вернуть ток значение, игнорируя, что есть незафиксированное изменение.
Итак, другими словами: ваш код будет выполняться только тогда, когда блокировка прошла успешно. (Другое ожидание², пока не будет снята предыдущая блокировка)
Обратите внимание, что с помощью FOR UPDATE
также заблокирует любой транзакционные выборы на время заблокирован — если вы не хотите этого, вы должны использовать LOCK IN SHARE MODE
вместо. Это позволит транзакционным выборам перейти к ток значение, при этом просто блокируя любое обновление или удаление оператора.
² запрос вернет ошибку по истечении времени, определенного с innodb_lock_wait_timeout
http://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_lock_wait_timeout
Потом вернется ОШИБКА 1205 (HY000): превышено время ожидания блокировки; попробуйте перезапустить транзакцию
Другими словами: это точка, в которой ваша попытка получить блокировку не удалась.
Sidenode: этот вид блокировки просто подходит для обеспечения целостности данных. (То есть ни одна строка, на которую ссылаются, не удаляется, пока вы вставляете что-то, ссылающееся на эту строку).
Как только блокировка снята, любая блокируется (или лучше позвоните задерживается) оператор delete будет выполнен, возможно, удалит только что вставленную строку из-за Cascading
в ряду, на котором вы только что держали замок, чтобы обеспечить целостность.
Если вы хотите создать систему, чтобы 2 пользователя не изменяли одни и те же данные одновременно, вы должны сделать это на уровне приложения и посмотреть на пессимистический против оптимистичный блокировка подходит, потому что не стоит поддерживать транзакции в течение длительного периода времени. (Я думаю, что в PHP ваши соединения с базой данных автоматически закрываются после каждого запроса в любом случае, вызывая неявную фиксацию для любой запущенной транзакции)
Других решений пока нет …