2013-08-27 3 views
0

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

....

У меня есть база данных links, позволяет сохранить его простым, 2 колонки

 
ID int(10) PK, Status enum('ready', 'in progress', 'complete'); 
1 'ready' 
2 'ready' 
3 'ready' 

....

Я тогда есть API, что при запросе возвращает Идентификатор «готового» элемента, этот API можно было бы назвать много раз одновременно, и я хочу, чтобы идентификатор выдавался только один раз.

....

API MySQL запросов ..

 
LOCK TABLES `links` WRITE 
SELECT ID FROM links WHERE status = 'ready' LIMIT 1 // gets a ready one 
UPDATE links SET status = 'in progress' WHERE ID = 'X' // updates the one just got from line above to be in progress (so not selected by another API call 
UNLOCK TABLES 

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

Это правильно? или лучший способ сделать такую ​​вещь? Поскольку это вызывает длительные задержки на трафике MySQL с некоторыми запросами, ожидающими 5 минут или около того, а затем MySQL поражает максимальные соединения и вызывает всевозможные другие проблемы.

Таблица InnoDB и относительно небольшая с примерно 165 тыс. Строк, с индексом статуса, заблаговременно за любые советы или указатели.

+0

Являются ли идентификаторы уникальными, т.е. созданы с каждым посетителем или установлены и назначены посетителю? – jeff

+0

Нет, это просто база данных, заполненная уникальными идентификаторами, и каждый вызов API должен давать другой идентификатор, а не обманывать. – blackout2063

ответ

0

Вам не нужно блокировать всю таблицу.
Вобще:

UPDATE links SET status = 'in progress' 
WHERE status = 'Ready' 
LIMIT 1; 

или, если вы хотите получить обновленный идентификатор, используйте:

start transaction; 
select id into @xx from links 
where status = 'Ready' 
limit 1 for update; 
update links set status = 'in progress' 
where id = @xx; 
commit; 

Эти команды будут работать в считывающей поручены уровне isloation и выше.
Поскольку в столбце «статус» есть индекс, MySql поместит блокировку записи только на одну обновленную строку на время транзакции, оставив другие строки разблокированными.

+0

Спасибо, это имеет смысл и работает, если я запускаю его в командной строке или phpmyadmin, но не на PHP, так как мне нужно будет сделать две транзакции, поэтому фиксация будет отправляться после каждого. Мне нужно, чтобы «id» возвращался как переменная вне запроса. – blackout2063

+0

Я плохо знаю PHP, но я нашел пример того, как обращаться с транзакциями SQL в PHP, посмотрите на эту ссылку: http://stackoverflow.com/questions/2708237/php-mysql-transactions- Примеры – krokodilko

+0

Ницца, сделанное с точки зрения транзакций в PHP по этой ссылке, похоже, что сейчас работает, - утром будет проходить тест и принять этот ответ. Заранее спасибо. – blackout2063

Смежные вопросы