选择并锁定一行,然后更新UPDATE

时间:2014-11-18 14:09:17

标签: php mysql

我有一个脚本从MySQL数据库中选择一行。 然后更新此行。像这样:

$statement = $db->prepare("SELECT id, link from persons WHERE processing = 0");
$statement->execute();
$row = $statement->fetch();

$statement = $db->prepare("UPDATE persons SET processing = 1 WHERE id = :id");
$success = $statement->execute(array(':id' => $row['id']));

该脚本同时多次调用此PHP代码。有时它选择行event,因为它应该是“processing = 1”,因为另一个脚本在确切的时间调用它。

我该如何避免这种情况?

3 个答案:

答案 0 :(得分:3)

你需要做的是在这里添加一些锁,以防止像你创建的那样的竞争条件:

UPDATE persons SET processing=1 WHERE id=:id AND processing=0

这样可以避免双重锁定。

要进一步改进此功能,请创建一个可用于声明的锁定列:

UPDATE persons
  SET processing=:processing_uuid
  WHERE processing IS NULL
  LIMIT 1

这需要VARCHAR索引processing列,用于声明默认值为NULL。如果您在结果中修改了一行,那么您已声明了一条记录,并可以使用以下方式使用它:

SELECT * FROM persons WHERE processing=:processing_uuid

每次尝试声明时,都会生成一个新的声明UUID键。

答案 1 :(得分:2)

尝试使用事务进行查询。在mysql dev site

了解它们

您可以使用以下代码包装代码:

$dbh->beginTransaction();

// ... your transactions here

$dbh->commit();

您将找到文档here

答案 2 :(得分:0)

使用SELECT FOR UPDATE

http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html

例如

SELECT counter_field FROM child_codes FOR UPDATE; UPDATE child_codes SET counter_field = counter_field + 1;

在事务中包装它,并在事务结束时释放锁。