2012-06-22 119 views
3

我有一個包含唯一產品ID列表的MySQL表(表A)。利用此表的應用程序使用多個線程,每個線程選擇一個錶行(最上面),使用API​​獲取產品數據並將其更新到不同的表(表B)。一旦完成,該線程將刪除表A中相應的產品ID行並選擇另一個進行工作(循環直到表A中的所有行都已刪除,而B表已更新)。mysql - 爲選擇查詢鎖定行?

如何防止我的應用程序的線程意外地在表A的同一行上工作?有沒有辦法鎖定一行被選中?

示例: 應用程序的線程1從表A選擇行-1。從API獲取並更新所有相關數據到表B需要大約10到15秒的時間。當發生這種情況時,線程2將觸發並檢查表A以選擇要處理的行。在這種情況下,我只需要鎖定行1,以便它不會線程2不會看到/讀取它,而是選擇第2行。

+2

看到的交易,樂觀/悲觀鎖等 – biziclop

回答

6

本地的MySQL鎖定不提供此功能。你可以使用一列來執行你的「鎖定」。

假設每個線程都有唯一的ID,你可以創建一個名爲thread_owner列,默認爲0

一個線程會抓住一排這樣的:

UPDATE mytable 
SET thread_owner = :my_threadID 
WHERE thread_owner = 0 
LIMIT 1 

然後選擇這樣的行(如果沒有要處理的行,它可能不會返回):

SELECT * 
FROM mytable 
WHERE thread_owner = :my_threadID 

然後處理它,最後刪除它。

該解決方案可以在MyISAM和InnoDB上運行。

但是,對於InnoDB,它可能會很慢,因爲每個UPDATE語句都試圖鎖定thread_owner = 0的所有行,除非您確定每次都以相同的順序鎖定所有行,否則它甚至可能造成僵局。所以,你可以嘗試明確鎖定整個表中的UPDATE語句:

LOCK TABLES mytable WRITE; 
UPDATE mytable 
SET thread_owner = :my_threadID 
WHERE thread_owner = 0 
LIMIT 1; 
UNLOCK TABLES; 

這樣一來,無論是MyISAM和InnoDB將同樣的方式工作。

+0

InnoDB支持行級鎖,MyISAM不。 Myisam有*併發*插入,但這不是一回事。請參見[條目9](https://en.wikipedia.org/wiki/Comparison_of_MySQL_database_engines)。 –

+0

@SpencerRathbun,你是不是要把這條評論發佈到我的文章上?它有什麼關係? –

+0

你指出'UPDATE'會因爲鎖定InnoDB上的所有行而出現問題,這是不正確的,因爲InnoDB沒有鎖定整個表,只是要更新的條目。 –

0

嘗試用「鎖表」命令,我用2個窗口向您展示:

jcho_1> lock table t1 write; 
Query OK, 0 rows affected (0.00 sec) 

jcho_2> select * from t1; 

jcho_2留等待釋放表能夠閱讀,當jcho_1做到這一點:

jcho_1> unlock tables; 
Query OK, 0 rows affected (0.00 sec) 

jcho_2能夠與他的查詢。

jcho_2> select * from t1; 
+----------+-------------+--------------+---------------------+ 
| actor_id | first_name | last_name | last_update   | 
+----------+-------------+--------------+---------------------+ 
|  206 | a   | b   | 0000-00-00 00:00:00 | 
|  71 | ADAM  | GRANT  | 2006-02-15 04:34:33 | 
|  132 | ADAM  | HOPPER  | 2006-02-15 04:34:33 | 
... 
|  0 | 0   | 0   | 0000-00-00 00:00:00 | 
+----------+-------------+--------------+---------------------+ 
202 rows in set (1 min 27.67 sec) 

enter image description here

enter image description here