2010-01-21 81 views
1

我在C API中使用mySQL,但这不应该是相关的。 我的代码必须处理符合某些条件的表中的记录,然后更新所述记录以将它们标记为处理完毕。表中的行被我不控制的另一个进程修改/插入/删除。我在下面很害怕,更新可能标志的一些记录错误,因为该集记录匹配的可能步骤1和步骤3SQL(mySQL)更新某个select所处理的所有记录中的某些值

SELECT * FROM myTable WHERE <CONDITION>; # step 1 
<iterate over the selected set of lines. This may take some time.> # step 2 
UPDATE myTable SET processed=1 WHERE <CONDITION> # step 3 

什么是聪明的方式,以确保之间已经改变了update更新所有的行处理,只有他们?交易似乎不符合该法案,因为它没有提供这种隔离:最近修改的记录不在最初选择的集合中,可能仍然是UPDATE语句的目标。出于同样的原因,SELECT ... FOR UPDATE似乎没有帮助,但它听起来很有前途:-)

我能看到的唯一方法是使用临时表来记忆要处理的行集,做类似的事情:

CREATE TEMPORARY TABLE workOrder (jobId INT(11)); 
INSERT INTO workOrder SELECT myID as jobId FROM myTable WHERE <CONDITION>; 
SELECT * FROM myTable WHERE myID IN (SELECT * FROM workOrder); 
<iterate over the selected set of lines. This may take some time.> 
UPDATE myTable SET processed=1 WHERE myID IN (SELECT * FROM workOrder); 
DROP TABLE workOrder; 

但是这看起来很浪费,效率也不是很高。

有什么更聪明的吗?

非常感谢来自SQL新手。

回答

1

我最终被使用,根据他们的状态标志线表中列解决了这个问题。这一栏让我来实现一个简单的状态机。从概念上讲,我有两个可能的值此状态:不

kNoProcessingPlanned = 0; #default "idle" value 
kProcessingUnderWay = 1; 

现在我的算法是这样的:

UPDATE myTable SET status=kProcessingUnderWay WHERE <CONDITION>; # step 0 

SELECT * FROM myTable WHERE status=kProcessingUnderWay; # step 1 
    <iterate over the selected set of lines. This may take some time.> # step 2 
UPDATE myTable SET processed=1, status=kNoProcessingPlanned WHERE status=kProcessingUnderWay # step 3 

有几个州行的这种想法可以扩展到更多国家需要

1

有几种选择:

  1. 你可以锁定表

  2. 您可以添加一个与foo_id IN(all_the_ids_you_processed)为更新条件。

  3. ,你可以选择之前更新,然后只选择更新的行(即通过处理日期)

+0

1-锁定表格意味着阻止另一个进程在我正在处理时工作。它不会很高兴... 2-没有临时表,你怎么能表达all_the_ids_you_processed?我提前对处理后的记录感到有些不舒服,所以我可以稍后选择它们,因为它是侵入性的:需要一个新的“timeStamp”列。另外,时间戳很棘手,因为时间并不总是单调的:例如它可以倒退(例如,当夏令时间关闭时)。 然后,临时表是一个非常糟糕的主意吗? – 2010-01-21 10:53:58

+0

而不是时间戳,使用多值状态字段。让未处理的行具有状态0(说);你做一个更新,将状态设置为1(意味着正在处理中),然后执行处理,然后执行另一个更新以将状态设置为2(表示进入处理)。 – 2010-01-21 21:29:38

+0

是的,我想这可以解决问题,因为我描述了它。但我最终决定记住客户端应用程序中已处理记录的ID。 – 2010-01-23 22:22:58

相关问题