我有以下算法:
还有状态2 - 行有答案并完成。
SELECT * FROM details WHERE RowStatus=0 AND taskid=".$task_id." ORDER BY RAND() LIMIT 1
UPDATE details SET RowStatus=1 ,Agent='".$_SESSION['username']."' where TaskID=".$row['TaskID']." and RowId=".$row['RowId']
问题在于,如果我剩下10行并且8个代理处理该任务,有时会发生他们在完全相同的时间内提交前一行。 然后他们两个选择同一行,只有其中一行用他的名字锁定行 意思是 - 其中一个正在同一行上工作。
它听起来像一个小问题但不知何故,我在2500行任务中发生了5-10次。 有没有办法在选择行的同时锁定行?阻止其他用户选择此行?
答案 0 :(得分:0)
你应该锁定行(当然,如果你使用的是InnoDB)。情景如下:
begin;
select ... FOR UPDATE;
doing what you want with task
update selected task
commit;
答案 1 :(得分:0)
一种方式(更好)是使用交易: PHP + MySQL transactions examples
第二个选项是首先进行UPDATE(锁定任务),然后按代理和状态进行SELECT任务。
答案 2 :(得分:0)
一种简单的方法可能是:
在UPDATE
之后,在该行上运行SELECT
并检查Agent
是否为当前用户。如果不是,请重新选择新行
答案 3 :(得分:0)
我知道如何在没有任何特殊访问,存储过程,触发器或事务的情况下执行此操作。
您需要创建一个名为Semaphores
的表,其中包含两列 - name (text)
和state (int)
。为了您的目的,我们将创建一个名为details
的行,状态为0。
然后你的代码看起来像这样:
$semaphore = query("UPDATE Semaphore SET state = 1 WHERE name = 'details'"); // It's just pseudo code for querying database - do it yourself
while(affected_rows($semaphore) == 0) {
$semaphore = query("UPDATE Semaphore SET state = 1 WHERE name = 'details'");
sleep(10); // sleep to not query too often
}
fetch_and_query("SELECT * FROM details WHERE RowStatus=0 AND taskid=".$task_id." ORDER BY RAND() LIMIT 1");
query("UPDATE details SET RowStatus=1 ,Agent='".$_SESSION['username']."' where TaskID=".$row['TaskID']." and RowId=".$row['RowId']);
query("UPDATE Semaphore SET state = 0");
这样,运行此查询的每个用户都必须等待其他人完成SELECT + UPDATE事务。另外它只是一个技巧 - 锁的工作是更新Semaphore表的部分,你只需要一个查询来查明锁的值是否为0.如果是,那么函数affected_rows
将告诉你,你可以继续你的脚本(请注意,affected_rows可能在PHP中,例如mysqli_affected_rows
,但也可以是任何其他等效的)。请记住,当您更新不需要更新的行时,此函数无论如何都将返回零值。
我在博客上的回答:http://kelostrada.pl/en/mysql-en/locking-rows-with-myisam-php/