2012-02-08 103 views
3

我有mysql表fg_stock。大多數情況下,此表中正在進行併發訪問。我用這個代碼,但它不工作:MYSQL表與PHP鎖定

<?php 
    mysql_query("LOCK TABLES fg_stock READ"); 

    $select=mysql_query("SELECT stock FROM fg_stock WHERE Item='$item'"); 

    while($res=mysql_fetch_array($select)) 
    { 
     $stock=$res['stock']; 
     $close_stock=$stock+$qty_in; 
     $update=mysql_query("UPDATE fg_stock SET stock='$close_stock' WHERE Item='$item' LIMIT 1"); 
    } 

    mysql_query("UNLOCK TABLES");  
?> 

這樣行嗎?

+0

'$ qty_in'從哪裏來?你的SQL對我來說沒有意義,看起來這樣做可以更容易。 – CodeZombie 2012-02-08 08:24:32

+0

如果您的SELECT返回多條記錄(您正在使用循環),則即使您放置了LIMIT,UPDATE也可能無法在迭代的相同記錄上工作。如果你的SELECT只返回一條記錄,你不需要循環,但循環不會傷害你的數據。 – thevikas 2012-02-08 09:22:34

回答

1

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

mysql> LOCK TABLES real_table WRITE, temp_table WRITE; 
mysql> INSERT INTO real_table SELECT * FROM temp_table; 
mysql> DELETE FROM temp_table; 
mysql> UNLOCK TABLES; 

所以你的語法是正確的。

也從另一個問題:

故障排除:您可以通過試圖與未鎖定另一個表工作 測試表鎖成功。如果您獲得鎖定,則 嘗試寫入未包含在鎖定語句 中的表格應該會生成錯誤。

您可能需要考慮替代解決方案。作爲 where子句的一部分, 不會執行鎖定,而是執行包含已更改元素的更新。如果您自 讀取之後更改的數據發生了更改,則更新將「失敗」並返回修改的零行。這 消除了表鎖,以及可能帶來的所有凌亂的恐怖,包括死鎖。 PHP, mysqli, and table locks?

4

「大多數時候,併發訪問該表中發生」

那麼,爲什麼要鎖定整個表時,很明顯,你正試圖從表中訪問特定行( WHERE Item ='$ item')?有可能你正在爲有問題的表運行MyISAM存儲引擎,你應該考慮使用InnoDB引擎,因爲它的一個優點是它支持行級鎖定,所以你不需要鎖定整個表。

4

爲什麼你需要鎖定你的表呢?

mysql_query("UPDATE fg_stock SET stock=stock+$qty_in WHERE Item='$item'"); 

就是這樣!無需鎖定表格,也不需要進行不必要的循環和查詢。例如,試圖通過在$ qty_in上使用intval php函數(當然,如果它是整數)來避免SQL注入。

而且,可能只有time concurrent access只是由於數據庫未經過優化的工作而發生的,並且查詢數量過多。

ps:此外,您的示例沒有任何意義,因爲mysql可以在循環中始終更新相同的記錄。你沒有告訴MySQL你想要更新哪個記錄。只告訴用Item ='$ item'更新一條記錄。在下一次迭代中,SAME記錄可能會再次更新,因爲MySQL不知道已更新的記錄與尚未觸及的記錄之間的差異。

+0

假設你的代碼可以兌換一個月的保費或其他東西。當有人贖回它時,你會檢查它是否存在,如果存在,則將其從數據庫中刪除。如果你不鎖定行,那麼你最終會有人刷新25次,並獲得25個月。 – apscience 2013-01-15 22:44:46