我有一个从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 代码。有时它会选择该行,即使它应该是"处理 = 1",因为另一个脚本在确切的时间调用它。
我怎样才能避免这种情况?
您需要做的是在此处添加某种锁,以防止像您创建的争用条件:
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 密钥。
尝试使用事务进行查询。在 mysql 开发站点上阅读有关它们的信息
您可以使用以下内容包装代码:
$dbh->beginTransaction();
// ... your transactions here
$dbh->commit();
您可以在此处找到文档。
使用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;
将其包装在事务中,当事务结束时,锁将被释放。