Php MySQL:同步访问

Php MySQL:同步访问,php,mysql,Php,Mysql,我有以下算法: 选择没有答案且未锁定的行(状态0) 锁定此行以防止其他人获取它(状态1) 还有状态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']." an

我有以下算法:

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

    您应该锁定该行(当然,如果您使用的是InnoDB)。情况如下:

    begin;
    select ... FOR UPDATE;
    
    doing what you want with task
    
    update selected task
    
    commit;
    
    一种方法(更好)是使用事务:

    第二个选项是首先进行更新(锁定任务),然后选择task by Agent and Status

    一个简单的方法可能是:


    更新
    之后,在该行上运行
    选择
    ,并检查
    代理
    是否为当前用户。如果不是,请重新选择一个新行

    我知道如何在没有任何特殊访问、存储过程、触发器或事务的情况下执行它

    您需要创建一个名为信号量的表,该表有两列-
    名称(text)
    状态(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");
    
    这样,运行此查询的每个用户都必须等待其他用户完成其选择+更新操作。另外,这只是一个技巧——锁的工作就是更新信号量表,您只需要一个查询来确定锁的值是否为0。如果是,那么函数
    impacted_rows
    将告诉您可以继续使用脚本(请注意,受影响的_rows可能在PHP中,例如
    mysqli_impacted_rows
    ,但也可以是任何其他等效代码)。请记住,当您更新一个不需要更新的行时,该函数将返回一个零值


    我在博客上的回答是:

    是否有任何真正的理由按兰德订购(),或者只是为了避免冲突?如果您正在处理
    InnoDB
    ,您可以使用事务起初我没有使用random,但随后它们获得同一行的机会会增加。不幸的是,不是InnoDB:(如果您不是在InnoDB上工作,而是在MyIsam上工作,那么唯一的选择就是锁定整个表。如果我不知道所选行是什么,如何锁定该行?