Есть ли способ для MySQL ждать строки, соответствующие условию вставки - PullRequest
6 голосов
/ 15 августа 2011

Допустим, я писал приложение, в котором мне нужно было бы получать уведомления в режиме реального времени с сервера, и, скажем, эти уведомления хранятся в базе данных mysql. Чтобы получить их, мне нужно будет продолжать опрашивать сервер MySQL (повторять тот же выбор запрос, пока я на самом деле не получу результаты), но я думаю, что это очень неэффективный способ сделать это, так как в большинстве случаев выбор будет пустым. Если я делаю это часто, это чрезмерная нагрузка на сервер, если я делаю это редко, уведомления приходят очень поздно. Поэтому мне было интересно, есть ли способ, например, чтобы запрос mysql блокировался до тех пор, пока не станет доступен результат, соответствующий условию.

list = query ("SELECT * FROM `notifications` WHERE `unread`=1") ;

вместо того, чтобы возвращать пустой список, если нет непрочитанных уведомлений, вместо этого он будет ждать, пока на самом деле будут непрочитанные уведомления, чтобы вернуть

1 Ответ

8 голосов
/ 15 августа 2011

Я рекомендую использовать шаблон производителя-потребителя , реализованный с новой таблицей в качестве «рабочей очереди».Нет необходимости в хранимой процедуре, потому что триггер очень прост.

  1. Триггер будет заполнять рабочую очередь
  2. Код будет опрашивать таблицу рабочей очереди.Поскольку таблица будет очень маленькой, запрос будет быстрым и с низкой нагрузкой.
  3. Код будет делать все, что вам нужно, и удалять строки из таблицы по окончании, сохраняя его как можно меньшим

Создайте таблицу с идентификатором notification для обработки и столбцом «статус обработки», например:

create table work_queue (
    id int not null auto_increment,
    notification_id int references notifications,
    status enum ('ready', 'processing', 'failed')
);

Создайте простой триггер, который заполняет таблицу рабочей очереди:

delimiter $
create trigger producer after insert on notifications
for each row begin 
    insert into work_queue (notification_id, status) 
    select new.id, 'ready'
    where new.unread;
end; $
delimiter ;

Ваш код будет иметь псевдокод:

  1. select * from work_queue where status = 'ready' order by id limit 1
  2. update work_queue set status = 'processing' where id = <row.id>
  3. Делайте то, что вам нужно notifications where id = <row.notification_id>
  4. или delete from work_queue where id = <row.id> или update work_queue set status = 'failed' where id = <row.id> (вам нужно выяснить, что делать с неисправными предметами)
  5. Сон 1 секунда (эта пауза должна быть примерно такой же, какпиковая частота поступления уведомлений - вам нужно настроить это для баланса между размером work_queue и нагрузкой на сервер)
  6. Перейти к 1.

Если у вас есть один опрос процесса, тамнет необходимости запирать заботы.Если у вас есть опрос нескольких процессов, вам нужно обработать условия гонки.

...