MySQL有没有一种方法可以等待符合条件的行被插入?

6
假设我正在编写一个应用程序,需要从服务器实时获取通知,而这些通知存储在MySQL数据库中。为了获取它们,我必须不断轮询MySQL服务器(重复相同的select查询,直到实际获得结果),但我认为这是一种非常低效的方式,因为大多数情况下,选择会变为空。如果我经常这样做,对服务器的负担是不合理的,如果我很少这样做,通知将会来得很晚。所以我想知道是否有一种方法,例如MySQL查询可以阻塞,直到满足条件的结果可用。
list = query ("SELECT * FROM `notifications` WHERE `unread`=1") ;

如果没有未读通知,则不返回空列表,而是等待实际上有未读通知才返回。

1个回答

10
我建议使用生产者消费者模式,采用新表作为“工作队列”进行实现。因为触发器非常简单,所以不需要存储过程。
  1. 触发器将填充工作队列
  2. 代码将轮询工作队列表。由于表格非常小,查询速度快,负载低。
  3. 代码将执行您需要的操作,并在完成后从表中删除行 - 使其尽可能小

创建一个具有要处理的通知的ID和“处理状态”列的表,例如:

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秒钟(这个暂停时间应该与通知到达率峰值大致相同 - 你需要调整以在工作队列大小和服务器负载之间平衡)
  6. 跳转到1.

如果你只有一个进程轮询,那么就不需要担心锁问题。如果你有多个进程轮询,则需要处理竞争条件。


有趣的想法,我认为除了轮询没有其他方法, 谢谢你的回答 :) - Aleksandras Coldberg Ševčenko
没有其他办法,所以您想让您的轮询尽可能快。我不得不说,这是我赚取的最艰难的10个声望点 :) - Bohemian
如果您想要减少所有这些轮询对数据库的负载,您可以让生产者为读取工作队列表而上锁,并仅在有可用工作时解锁它。 - Arie Skliarouk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接