我有一个脚本从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”,因为另一个脚本在确切的时间调用它。
我该如何避免这种情况?
答案 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;
在事务中包装它,并在事务结束时释放锁。