MYSQL确保两个cronjobs不处理相同的请求

时间:2012-05-07 18:19:36

标签: php mysql database security

这是我的问题:

在我的数据库中,我有一个请求表,它有一个状态字段。 cronjob每分钟运行一次,查找具有“待处理”状态的每个请求。处理完请求后,它会将状态设置为“已完成”。

有时这个cronjob需要一分钟才能运行,所以两个相同的cronjob正在运行。我需要确保他们不处理相同的请求。

现在我正在这样做:

$requests = db_all($this->db->query('SELECT * FROM x__mx_request WHERE status="pending"'));
//few lines of code later
$this->db->query('UPDATE x__mx_request SET status="processing" WHERE id IN('.implode(',', $ids).')');

我选择它后将状态设置为处理,这会阻止其他脚本处理它,但是一个脚本是否可能选择所有请求,然后第二个脚本在第一个脚本将它们设置为之前选择所有请求处理?

我想要一种更安全的方式来做到这一点!

编辑:感谢您提供了很好的答案,但在我将其标记为正确之前,我必须先试用它们。

3 个答案:

答案 0 :(得分:2)

您可以尝试制作一个锁定/解锁文件,以便cronjobs可以检查“知道”作业是否已经/正在运行。 如果出现故障,没有响应等,也可以使用进程pid来识别进程的状态。

答案 1 :(得分:1)

将状态设置为唯一值,然后使用该唯一值处理所有内容。如果您的处理在一半时间内失败,则会出现超时或某种后退(但无论如何您需要处理当前情况)。

类似的东西(我只是编造PHP,因为我不是特别懂语言):

 $guid = new_guid();

 $this->db->query(
    'UPDATE x__mx_request SET status = ? WHERE status = "pending";', 
    $guid
 );
 $requests = db_all(
    $this->db->query('SELECT * FROM x__mx_request WHERE status = ?;', $guid)
 );

另一个选择是交易 - 但我认为你需要SERIALIZABLE,这意味着你基本上只能处理一个作业处理。如果你想这样做,你的cron作业的锁文件可以在不改变代码的情况下轻松完成。

答案 2 :(得分:0)

transactions是你想要的。因此,您只需一个事务来读取数据,将待处理状态更改为某个中间值(如inprocess),然后返回数据。

这可以防止两个查询返回相同的数据。

大概你想要像这样的伪sql

begin transaction 

select into tmp table * from blah where status = "pending"

update status = "being processed" where id in tmp 

end transaction 

return select * from tmp table