2011-02-11 101 views
2

我有一个表格“命令可以做”与状态(“麦克罗公司一直供应”,“加工”,“完成”)行锁的更新状态

我有几个实例(亚马逊EC2)与守护问为“要做的命令”。

守护进程请求状态为“toprocess”的行,然后进行处理,并在每个循环结束时将状态更改为“完成”。

问题是,在开始该循环之前,我需要将所有行'toprocess'更改为状态'processing',所以其他实例不会采用相同的行,从而避免冲突。

我读过有关InnoDB的行锁,但我不明白他们很好...

SELECT *从那里状态=“麦克罗公司一直供应” 然后我需要这些结果的ID的命令,并将状态更新为'处理',锁定这些行直到它们更新。

我该怎么办?

谢谢

回答

0

据我知道你不能使用MySQL来锁定行(使用内置的方法)。你有两个选择,但:

  1. 如果您的表不应该由任何其他进程读取,直到锁被释放,那么你可以使用表级锁as described here

  2. 你可以实现你自己的基本行锁定通过更新你正在处理的每一行中的一个值,然后让所有其他的守护进程检查这个属性是否被设置(一个BIT数据类型就足够了)。

InnoDB锁定在行级读取和更新,但是如果你想锁定任意时间段的行,那么你可能必须去第二个选项。

+0

嗨,...表锁定太多“沉重”(思考在应用程序的其余部分)...你告诉的第二个选择似乎解决方案...我怎么能做到这一点? – FlamingMoe 2011-02-11 17:22:18

1

的可能(但不是很优雅)的解决方案可能是第一个更新的记录,然后读取其数据:

每个守护进程都会有一个唯一的ID,并且该表将有一个名为“所有者”新列为那个ID。 然后,deamon将运行类似于“更新表SET状态='处理',所有者='theDeamonId'其中status ='toprocess'... LIMIT 1”

当更新运行行被锁定,其他deamon可以阅读它。 更新后,此行由特定的deamon拥有,然后它可以运行SELECT从该行获取所有必要的数据(WHERE status ='processing'AND owner ='theDeamonId')。

最后,最后一次UPDATE会将该行设置为'已处理',并且可能(或可能不)删除所有者字段。将它保留在那里也会使关于deamons工作的一些统计数据成为可能。

3

你会使用一个事务,并读取用于更新的数据,这将阻止其他选择,其中包括那个被选中

begin transaction; 
select * from commands where status = 'toprocess' for update; 
for each row in the result: 
    add the data to an array/list for processing later. 
    update commands set status='processing' where id = row.id; 

commit; 

process all the data 

了解一点关于FOR UPDATE的行FOR UPDATE,和InnoDB isolation levels