行锁定更新状态

时间:2011-02-11 17:03:57

标签: mysql locking innodb row

我有一个“命令要做”的状态表('toprocess','processing','done')

我有几个实例(amazon ec2),一个守护进程要求“命令”。

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

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

我已经读过有关innodb行锁的信息,但我对它们并不了解......

SELECT * from status where status ='toprocess' 然后我需要获取这些结果的ID,并将状态更新为'processing',锁定这些行直到它们被更新。

我该怎么做?

谢谢

3 个答案:

答案 0 :(得分:3)

您使用了一个事务,并使用FOR UPDATE读取数据,这将阻止在被选中的行上包含FOR UPDATE的其他选择

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和InnoDB isolation levels

答案 1 :(得分:1)

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

每个deamon都有一个唯一的ID,该表将有一个名为“owner”的新列。 然后deamon将运行类似“UPDATE table SET status ='processing',owner ='theDeamonId',其中status ='toprocess'... LIMIT 1”

更新运行时,行被锁定,因此没有其他守护程序可以读取它。 更新后,此行由特定守护程序拥有,然后它可以运行SELECT以从该行获取所有必需的数据(WHERE status ='processing'AND owner ='theDeamonId')。

最后,最后一次更新会将行设置为“已处理”,并且可能(或可能不会)删除所有者字段。保持它在那里也将有关于守护者工作的一些统计数据。

答案 2 :(得分:0)

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

  1. 如果在释放锁之前任何其他进程都不应读取您的表,那么您可以使用表级锁定as described here

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

  3. InnoDB在行级锁定无论如何都要进行读取和更新,但是如果你想在任意时间内锁定行,那么你可能不得不使用第二个选项。