2012-04-16 61 views
1

函數有一個結構:MySQL的MyISAM的競爭條件

$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

哪裏鎖定表的代碼? – 2012-04-16 18:56:59

+0

對不起,問題更新 – Merlin 2012-04-16 19:02:53

+0

您的用戶是否擁有LOCK TABLES特權? – angrychimp 2012-04-16 19:30:55

回答

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設置爲0即可。也就是你發佈的代碼也是這樣的,但是對於我而言並不是很明顯你想要使用這個代碼:)

更一般地說,如果你使用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/

+0

這裏要複雜得多 – Merlin 2012-04-16 19:37:32

+0

在這種情況下,當然,您將不得不向我們展示特定的代碼。 – Daan 2012-04-16 19:38:31

+0

我的存儲引擎是myisam,鎖表應該適用於這種情況。但沒有幫助( – Merlin 2012-04-16 19:40:19