这可能是我第十次实施这样的事情,而且我从未对我提出的解决方案百分百满意.
使用mysql表而不是"正确"的消息传递系统的原因很有吸引力,主要是因为大多数应用程序已经将一些关系数据库用于其他东西(对于我一直在做的大多数事情,它往往是mysql),而很少有应用程序使用消息传递系统.此外 - 关系数据库具有非常强大的ACID属性,而消息传递系统通常没有.
第一个想法是使用:
create table jobs( id auto_increment not null primary key, message text not null, process_id varbinary(255) null default null, key jobs_key(process_id) );
然后入队看起来像这样:
insert into jobs(message) values('blah blah');
出列似乎是这样的:
begin; select * from jobs where process_id is null order by id asc limit 1; update jobs set process_id = ? where id = ?; -- whatever i just got commit; -- return (id, message) to application, cleanup after done
表和入队看起来不错,但出队有点困扰我.回滚的可能性有多大?还是被封锁了?我应该用什么键来制作O(1)-ish?
或者,我正在做什么更好的解决方案?
你的出队可能更简洁.您可以在没有显式事务的情况下在一个原子语句中执行此操作,而不是依赖于事务回滚:
UPDATE jobs SET process_id = ? WHERE process_id IS NULL ORDER BY ID ASC LIMIT 1;
然后你可以用(括号[]表示可选,取决于你的具体情况)拉取作业:
SELECT * FROM jobs WHERE process_id = ? [ORDER BY ID LIMIT 1];
我已经构建了一些消息排队系统,我不确定你指的是什么类型的消息,但是在出列的情况下(是一个单词吗?)我做了同样的事情你已经完成了.您的方法看起来简单,干净,坚固.并不是说我的工作是最好的,但事实证明它对许多网站的大型监控非常有效.(错误记录,大量电子邮件营销活动,社交网络通知)
我的投票:不用担心!
Brian Aker刚才谈到了一个队列引擎.一直在谈论SELECT table FROM DELETE
语法.
如果您不担心吞吐量,可以始终使用SELECT GET_LOCK()作为互斥锁.例如:
SELECT GET_LOCK('READQUEUE'); SELECT * FROM jobs; DELETE FROM JOBS WHERE ID = ?; SELECT RELEASE_LOCK('READQUEUE');
如果你想变得非常花哨,请将其包装在存储过程中.