2010-10-07 4 views
18

У меня есть таблица user с полем lastusedecnumber.Как заблокировать один ряд

Мне нужно открыть и увеличить lastusedecnumber.

Во время этого времени доступа мне нужно заблокировать эту конкретную строку пользователя (а не всю таблицу).

Как это сделать?

Тип таблицы: MyISAM.

+5

[Только InnoDB имеет блокировку ряда; MyISAM, MEMORY и MERGE - это уровень таблицы] (http://dev.mysql.com/doc/refman/5.1/en/internal-locking.html) –

+1

Обязательно ознакомьтесь с другими вопросами Stackoverflow относительно блокировок на уровне строк что вы делаете образованный выбор. – belwood

ответ

22

MySQL использует только блокировку на уровне таблицы из таблиц MyISAM. Если вы можете, переключитесь на InnoDB для блокировки на уровне строк.

Вот ссылка на сайт MySQL, описывающий блокировки, установленные операторами SQL для таблиц InnoDB. http://dev.mysql.com/doc/refman/5.0/en/innodb-locks-set.html

+0

Эта блокировка работает только для этой транзакции или она является постоянной для всей базы данных? –

+0

Иногда для транзакции, иногда глобальной. Перед использованием внимательно прочитайте и поймите. Например, существуют различные типы блокировок, такие как «глобальная блокировка чтения». Иногда блокировки автоматически освобождаются при фиксации, другие могут быть выпущены в начале транзакции. Ваши требования должны диктовать какой тип блокировки вы должны использовать и как ее использовать. – belwood

1

В качестве временного решения можно добавить столбец в таблицу, как locked TINYINT(1) - всякий раз, когда вы хотите, чтобы строка для блокировки вы установите его в 1. Когда вы пытаетесь получить доступ к этой строке, первое, что вы делаете, это проверить, установлены ли поля locked.

Чтобы разблокировать строку, просто установите ее на 0. Нехорошо, но очень простой обходной путь.

+0

Если соединение закрыто, как закрыть браузер или т. Д. Если он автоматически разблокируется для других? Я думаю, что это не так. Я правильно? – svk

+0

Нет, конечно, этого не произойдет. Вы могли бы предоставить какую-то работу, которая периодически проверяет, существует ли открытый сеанс для пользователя, который вызвал блокировку строк. Конечно, вы должны добавить некоторую пользовательскую информацию в таблицу. – dhh

+6

Но это похоже на плохой семафор, который не устраняет условия гонки. Если 2 параллельных запроса думают 'LOCK = 0', то они оба переходят в критический раздел, _both_ устанавливают' LOCK = 1', и у вас есть скрытая ошибка состояния гонки. – bobobobo

-1

Лучшим обходным путем является создание столбца, содержащего временную метку. Всякий раз, когда вы хотите заблокировать строку, вы обновляете ее до текущего времени. Чтобы разблокировать обновление до времени не менее x минут в прошлом. Затем, чтобы проверить, заблокирована ли его проверка того, что отметка времени не менее 6 минут.

Этот способ, если процесс выходит из строя (или пользователь никогда не завершает свою работу), блокировка эффективно заканчивается через x минут.

+2

Нет ничего хорошего - поскольку проверка и обновление не являются одной операцией, это позволяет двум соединениям блокировать одну и ту же строку, не зная друг о друге. (Вероятно, есть способ сделать это правильно, но было бы сложно и легко испортить.) – Brilliand

+0

Никогда НИКОГДА не используйте синхронизацию в качестве замены для блокировки. –

2

Вид поздно, но надеюсь, что это поможет кому-то:

UPDATE user SET lastusedecnumber = LAST_INSERT_ID(lastusedecnumber + 1); 
SELECT LAST_INSERT_ID(); 

Даст вам атомное приращение lastusedecnumber и умение читать новое значение lastusedecnumber поля (после приращения), используя SELECT LAST_INSERT_ID().

+8

Непонятно, как это связано с блокировкой строки ... – Brilliand

+0

Это хорошее предложение, так как оно позволяет вам обновлять строку и читать значение (хотя, как написано в настоящее время, оно считывает обновленное значение, а не старое один). В нем не упоминается, что, поскольку это запись в таблицу, она блокирует всю таблицу, пока она обновляет строку, поскольку это то, что делает MyISAM - этого нельзя избежать. – davidsheldon

0

Мне не хотелось конвертировать всю мою базу данных из myisam. Поэтому я просто пытаюсь создать новую таблицу с именем на основе идентификатора записи, которую я хочу заблокировать. Если создать таблицу успешно, выполните мою работу и удалите таблицу в конце. Если создать таблицу не удалось, остановите ее.