MySQL MyISAM竞争条件

时间:2012-04-16 18:56:09

标签: php mysql myisam race-condition

该功能具有下一个结构:

$q = 'LOCK TABLES table1 WRITE;';
mysql_query($q);    
$q = 'select id from table1 where is_delete = 0 limit 1;';
$res = mysql_fetch_assoc(mysql_query($q));
if($res) {
$q = 'UPDATE table1 SET is_delete = 1 WHERE id = '".$res['id']."'';
mysql_query($q);
}
$q = 'UNLOCK TABLES;';
mysql_query($q);

我锁定了所有表,但查询并行运行。 如何解决这个问题?

1 个答案:

答案 0 :(得分:0)

检查您是否在LOCK TABLES查询中收到任何MySQL错误:

$q = 'LOCK TABLES table1 WRITE';
$r = mysql_query($q) or die(mysql_error());    

但是,如果你正在做所有,你也可以简单地写一下:

UPDATE `table1 SET `is_delete` = 1 WHERE `is_delete` = 0 LIMIT 1

根本不需要任何锁定。当然,这只有在第一个查询中的数据没有以任何方式处理时才会起作用,并且如果您正在更新哪一行并不重要,只要它是is_delete设置的那一行。这就是你发布的代码也是如此,但对我来说,你想要使用这段代码的目的并不是很明显:)

更一般地说,如果您使用MySQL表的默认InnoDB存储引擎,您可能需要查看SELECT ... FOR UPDATE: http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html

你可以写:

$q = 'select id from table1 where is_delete = 0 limit 1 for update';
$res = mysql_fetch_assoc(mysql_query($q));

if($res) {
   $q = 'UPDATE table1 SET is_delete = 1 WHERE id = '".$res['id']."'';
   mysql_query($q);
}

另请参阅:http://www.mysqlperformanceblog.com/2006/08/06/select-lock-in-share-mode-and-for-update/