0

我试图将表中的一行锁定为“正在使用”,这样当我的 cron 每分钟运行一次时,我就不会处理两次数据。由于我的脚本运行所需的时间长度,cron 将导致脚本的多个实例同时运行(通常一次运行大约 5 或 6 个)。出于某种原因,我的“使用中”方法并不总是有效。

不想锁定这些表,因为我需要它们可用于同时处理,这就是为什么我使用“inuse”字段来伪锁定单个行的原因。我不知道有更好的方法来做到这一点。

这是我的困境的一个例子:

 <?
    //get the first row from table_1 that is not in use
    $result = mysqli_query($connect,"SELECT * FROM `table_1` WHERE inuse='no'");
    $rows = mysqli_fetch_array($result, MYSQLI_ASSOC);
    $data1 = $rows[field1];

    //"lock" our row by setting inuse='yes'
    mysqli_query($connect,"UPDATE `table_1` SET inuse='yes' WHERE field1 = '$data1'");

    //insert new row into table_2 with our data if it doesn't already exist
    $result2 = mysqli_query($connect,"SELECT * FROM `table_2` WHERE field='$data2'");
    $numrows = mysqli_num_rows($result2);
    if($numrows >= 1) { 
      //do nothing
    } else {
      //run some unrelated script to get data
      $data2 = unrelatedFunction();

      //insert our data into table_2
      mysqli_query($connect,"INSERT INTO `table_2` (field) value ('$data2')");
    }

    //"unlock" our row in table_1
    mysqli_query($connect,"UPDATE `table_1` SET inuse='no' WHERE field1 = '$data1'");
 ?>

您将在此处看到,如果 $data2 已存在一行,则不会收集和插入 $data2,但该部分用于错误检查,并且由于错误仍然存​​在,因此无法回答我的问题。我试图理解为什么(如果我没有在那里进行错误检查)我的“使用”方法有时会被忽略,并且我在 table_2 中得到重复的行,其中包含 $data2。

4

1 回答 1

1

在您的第一次选择和第一次更新之间有很多时间,另一个进程可以执行相同的操作。您也没有使用事务,因此您不能保证更改的任何顺序对其他人可见。

您可以使用所需的隔离级别将所有内容移动到事务中并使用SELECT .... FOR UPDATE 语法。或者您可以尝试以不同的方式进行复制。例如更新要处理的 N 行和SET in_use=your_current_pid WHERE in_use IS NULL. 然后,您可以回读您手动标记以进行处理的行。完成后,将 in_use 重置为NULL.

于 2013-09-08T22:16:56.597 回答