2013-08-27 86 views
0

這是我從未完全掌握的東西,並且想知道我是否正確地進行了操作並對其進行了檢查。MySQL表鎖定(閱讀)

....

我有一個數據庫links,讓我們保持它的簡單,2列

 
ID int(10) PK, Status enum('ready', 'in progress', 'complete'); 
1 'ready' 
2 'ready' 
3 'ready' 

....

然後,我有一個API,當查詢返回'準備好'項目的ID,這個API可以被多次同時調用,並且我想確保只給出一次該ID。

....

API的MySQL查詢..

 
LOCK TABLES `links` WRITE 
SELECT ID FROM links WHERE status = 'ready' LIMIT 1 // gets a ready one 
UPDATE links SET status = 'in progress' WHERE ID = 'X' // updates the one just got from line above to be in progress (so not selected by another API call 
UNLOCK TABLES 

因此,如果兩個API調用打它拆開0.01秒,第一個應該鎖定表它正在進行更新到,解鎖後第二個得到它的機會,並做同樣的事情,但選擇一個不同的ID到第一個得到。

這是正確的嗎?或者做這種事情的最佳方式?由於它似乎會導致MySQL流量出現長時間的延遲,一些查詢等待5分鐘左右,然後MySQL命中最大連接並導致各種其他問題。

該表是InnoDB,相對較小,約165k行,狀態索引,預先感謝您的任何建議或指針。

+0

身份證是唯一的,即與每個訪客一起創建或設置並分配給訪問者? – jeff

+0

不,這只是一個充滿了具有唯一ID的東西的數據庫,每次調用API都應該提供一個不同的ID,沒有模糊。 – blackout2063

回答

0

您不需要鎖定整個表格。
只是做:

UPDATE links SET status = 'in progress' 
WHERE status = 'Ready' 
LIMIT 1; 

,或者,如果你想獲取更新的ID,使用:

start transaction; 
select id into @xx from links 
where status = 'Ready' 
limit 1 for update; 
update links set status = 'in progress' 
where id = @xx; 
commit; 

這些命令將在讀COMMITED isloation水平和更高的工作。
由於在'status'列上有索引,因此MySql將在事務持續時間內將一個寫鎖定僅放置在一個更新的行上,而將其他行解鎖。

+0

謝謝,這是有道理的,如果我在命令行或phpmyadmin運行它,但不是在PHP中,因爲我需要做兩個事務,因此提交將在每個之後發送。我需要將「id」作爲查詢外的變量返回。 – blackout2063

+0

我不太瞭解PHP,但是我找到了一個例子來說明如何在PHP中處理SQL事務,看看這個鏈接:http://stackoverflow.com/questions/2708237/php-mysql-transactions-示例 – krokodilko

+0

不錯,通過該鏈接獲得了PHP中的事務處理意義,這似乎現在正在工作 - 應在早上再次測試並接受此答案。提前致謝。 – blackout2063