关于cron的MySQL查询重叠,忽略'锁定'行

时间:2013-09-08 22:00:40

标签: php mysql

我正在尝试将表中的一行锁定为“正在使用”,这样当我的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,但该部分用于错误检查,并且由于错误仍然存​​在而无法回答我的问题。我试图理解为什么(如果我没有那里的错误检查)我的'inuse'方法有时被忽略,我在table_2中得到重复的行,其中包含$ data2。

1 个答案:

答案 0 :(得分:1)

在第一次选择和第一次更新之间有很多时间,其他进程可以执行相同的操作。您也没有使用交易,因此您无法保证其他人可以看到任何更改顺序。

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