PHP - пример блокировки уровня строки MySQL
Я видел много постов, объясняющих использование 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();
В этом случае, как определить, была ли моя блокировка успешной? Каков наилучший способ обработки сценария, когда строка уже заблокирована?
Извините, если это где-то описано, но все, что мне кажется, это объяснения "счастливого пути".
1 ответ
В этом случае, как определить, была ли моя блокировка успешной? Каков наилучший способ обработки сценария, когда строка уже заблокирована?
Если строка, которую вы пытаетесь заблокировать , уже заблокирована - сервер mysql не вернет никакого ответа для этой строки. Он будет ждать², пока транзакция блокировки не будет зафиксирована или откатана.
(Очевидно: если строка уже была удалена, ваш SELECT
вернет пустой набор результатов и ничего не заблокирует)
После этого он вернет последнее значение, зафиксированное транзакцией, которая удерживала блокировку.
регулярное Select
Заявления не будут заботиться о блокировке и возвращают текущее значение, игнорируя, что есть незафиксированное изменение.
Итак, другими словами: ваш код будет выполняться только тогда, когда блокировка прошла успешно. (Другое ожидание², пока не будет снята предыдущая блокировка)
Обратите внимание, что с помощью FOR UPDATE
также заблокирует любые транзакционные SELECTS на время блокировки - если вы не хотите этого, вы должны использовать LOCK IN SHARE MODE
вместо. Это позволит транзакционным выборам продолжить текущее значение, в то же время просто блокируя любое обновление или оператор удаления.
² запрос вернет ошибку по истечении времени, определенного с innodb_lock_wait_timeout
http://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html Затем он вернет ОШИБКУ 1205 (HY000): превышено время ожидания блокировки;попробуйте перезапустить транзакцию
Другими словами: это тот момент, когда ваша попытка получить блокировку не удалась.
Sidenode: этот тип блокировки подходит для обеспечения целостности данных. (Т.е. ни одна строка, на которую ссылаются, не удаляется, пока вы вставляете что-то, ссылающееся на эту строку).
После снятия блокировки будет выполнен любой заблокированный (или, лучше сказать, отложенный) оператор удаления, возможно, удаляющий только что вставленную строку из-за Cascading
в ряду, на котором вы только что держали замок, чтобы обеспечить целостность.
Если вы хотите создать систему, чтобы избежать одновременного изменения двумя пользователями одних и тех же данных, вы должны сделать это на уровне приложения и взглянуть на пессимистические и оптимистичные блокировочные подходы, потому что не рекомендуется поддерживать транзакции в течение длительного времени. промежуток времени. (Я думаю, что в PHP ваши соединения с базой данных автоматически закрываются после каждого запроса в любом случае, вызывая неявную фиксацию для любой запущенной транзакции)