Почему LOCK TABLES [table] WRITE не предотвращает чтение таблицы?

Согласно http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html если я заблокирую таблицу для записи в mysql, никто другой не должен иметь доступа, пока она не будет разблокирована. Я написал этот скрипт, загруженный как script.php или script.php?l=1 в зависимости от того, что вы хотите сделать:

if ($_GET['l'])
{
    mysqli_query("LOCK TABLES mytable WRITE");
    sleep(10);
    mysqli_query("UNLOCK TABLES");
}
else
{
    $res=mysqli_query("SELECT * FROM mytable");
    // Print Result
}

Если я загружу script.php?l=1 в одном окне браузера, то, пока он спит, я смогу загрузить script.php в другом окне, и он должен дождаться завершения script.php?l=1, верно?

Дело в том, что script.php загружается сразу, несмотря на то, что script.php?l=1 имеет блокировку записи. Если я попытаюсь вставить в script.php, он будет ждать, но почему разрешен SELECT?

Примечание: я не ищу дискуссий о том, следует ли использовать LOCK TABLES или нет. На самом деле я, вероятно, собираюсь пойти с транзакцией, я сейчас исследую это, прямо сейчас я просто хочу понять, почему вышеизложенное не работает.


person Ben Holness    schedule 02.09.2013    source источник
comment
Может ли ваш PHP быть настроен на использование общих соединений mysql?   -  person Barmar    schedule 02.09.2013
comment
Я проверю, но если да, то почему INSERT задерживает, а SELECT нет?   -  person Ben Holness    schedule 02.09.2013
comment
Я только что попробовал из командной строки mysql>, и блокировка сработала так, как вы ожидали.   -  person Barmar    schedule 02.09.2013
comment
Похоже, это может быть как-то связано с кэшированием запросов. Я тоже пробовал в командной строке. В первый раз это сработало (SELECT был отложен), во второй раз - нет (SELECT был мгновенным), однако, как только я внес изменения в таблицу в сеансе блокировки, SELECT снова был задержан. Я думаю, это имеет какой-то смысл, но это не то, что, по его словам, должно делать. Если я НАПИШУ БЛОКИРОВАТЬ таблицу, она должна быть ЗАБЛОКИРОВАНА. Текущее поведение может нарушить мой процесс.   -  person Ben Holness    schedule 02.09.2013
comment
На самом деле, добавление SQL_NO_CACHE в запрос SELECT заставляет его работать!   -  person Ben Holness    schedule 02.09.2013


Ответы (2)


Это происходит из-за кэширования запросов. Доступен результат кэширования, который не «влияет» на блокировку, поэтому результаты возвращаются.

Этого можно избежать, добавив в выбор ключевое слово "SQL_NO_CACHE":

SELECT SQL_NO_CACHE * FROM mytable
person Ben Holness    schedule 02.09.2013
comment
Спасибо. Вы экономите мое время. - person Nguyen Van Vinh; 30.10.2017

Пункт LOCK заключается в том, чтобы другие сеансы не изменяли таблицу, пока вы используете ее во время вашего конкретного сеанса.

Причина, по которой вы можете выполнить запрос SELECT, заключается в том, что он по-прежнему считается частью того же сеанса MySQL, даже если вы открываете новое окно.

person ಠ_ಠ    schedule 02.09.2013
comment
Согласно MySQL, блокировка WRITE предотвращает любой доступ к таблице. В противном случае в чем разница между блокировками READ и WRITE? Что касается того же сеанса MySQL, я не верю в это по двум причинам. 1: Мой INSERT был заблокирован и 2: вместо другого окна браузера я могу сделать это на другом компьютере/IP, и это все еще происходит - person Ben Holness; 02.09.2013
comment
См. dev.mysql.com/doc/refman/5.0/en. /lock-tables.html: сеанс, удерживающий блокировку, может читать и записывать таблицу. - person ಠ_ಠ; 02.09.2013
comment
Для блокировок READ: сеанс, удерживающий блокировку, может читать таблицу (но не записывать ее). - person ಠ_ಠ; 02.09.2013
comment
Как вы думаете, почему это один и тот же сеанс MySQL (и если это так, то почему INSERT задерживается?) - person Ben Holness; 02.09.2013