Пессимистическая блокировка записи?

Я создаю веб-службу WCF для приложения Silverlight, и мне нужно, чтобы запись была заблокирована для чтения и записи при изменении.

Я использую MySQL версии 5.5.11.

Чтобы быть более конкретным, я хотел бы предотвратить запрос на чтение данных из строки при ее изменении.

Две SQL-команды для UPDATE и SELECT на самом деле довольно просты, например:

Обновление (должно быть заблокировано для записи/чтения):

UPDATE user SET user = ..... WHERE id = .....

Выберите (не должно быть возможности чтения при блокировке из приведенного выше запроса):

SELECT * FROM user WHERE id = .....

Вот что я пробовал, но, похоже, это не работает или вообще ничего не блокирует:

START TRANSACTION;
   SELECT user
   FROM user
   WHERE id = 'the user id'
   FOR UPDATE;

   UPDATE user
   SET user = 'the user data'
   WHERE id = 'the user id';
COMMIT;

person SlashJ    schedule 06.06.2012    source источник
comment
Зачем вообще выполнять это в транзакции? UPDATE работает атомарно сам по себе. Тем не менее, то, что вы пытаетесь, все еще должно работать; что заставляет вас думать, что это не так?   -  person eggyal    schedule 06.06.2012


Ответы (2)


Как вы определяете, что он не блокирует запись?

Когда запрос выполняется для таблицы с блокировками, он будет ожидать освобождения блокировок или, в конечном итоге, истечения времени ожидания. Ваша транзакция обновления произойдет так быстро, что вы даже не сможете сказать, что она заблокирована.

Единственный способ определить наличие проблемы — это если у вас был запрос, который выполнялся после запуска транзакции, но возвращал исходное значение для пользователя вместо обновленного значения. Это случилось?

Я бы просто поместил это в комментарий, но он был слишком длинным, но я обновлю его более полным ответом, основанным на вашем ответе.

person Brandon Moore    schedule 06.06.2012
comment
Привет, должен ли SQL-запрос в моем исходном сообщении также препятствовать чтению данных из этой строки другим запросом? В моем случае, похоже, произошло то, что, пока запись находилась в процессе изменения, другая запись смогла прочитать из нее данные И/ИЛИ вернула старое значение. Это веб-приложение, не знаю, имеет ли это значение. - person SlashJ; 06.06.2012
comment
Ваша транзакция продлится небольшую долю секунды. Вероятность того, что другой запрос даже сможет начаться в течение этого небольшого промежутка времени, довольно мала для начала. Возможно, запрос, возвращающий старое значение, был запущен до начала вашей транзакции обновления. Похоже, вы еще не убедились, что это действительно проблема, и я подозреваю, что проблема заключается в другом. - person Brandon Moore; 06.06.2012
comment
@Armz Кроме того, я не использую mysql, поэтому я не эксперт в том, как он блокирует, но я думаю, что вы, вероятно, неправильно понимаете, когда вам нужно использовать FOR UPDATE. Если вы обновляете только одну таблицу, строки должны быть заблокированы, и вам не нужно блокировать их самостоятельно. Проблема заключается в том, что вам нужно, например, убедиться, что выполняется несколько задач, прежде чем снимать блокировку таблицы. Чтобы строки были заблокированы между несколькими операторами обновления, вы должны использовать FOR UPDATE, чтобы держать их заблокированными все время. Но я считаю, что для одного оператора обновления это избыточно и не нужно. - person Brandon Moore; 06.06.2012

MySql использует многоверсионный контроль параллелизма по умолчанию (и это очень и очень неплохое поведение вместо MSSQL). Попробуйте использовать блокировку чтения (LOCK IN SHARE РЕЖИМ) для достижения желаемого.

person Dennis    schedule 06.06.2012