MySQL:同时访问

时间:2014-02-20 10:22:28

标签: php mysql

我有以下算法:

  1. 选择没有答案且未锁定的行(状态0)
  2. 锁定此行以防止他人获取(状态1)
  3. 还有状态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次。 有没有办法在选择行的同时锁定行?阻止其他用户选择此行?

4 个答案:

答案 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/