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 ваши соединения с базой данных автоматически закрываются после каждого запроса в любом случае, вызывая неявную фиксацию для любой запущенной транзакции)

Другие вопросы по тегам