佇列是常用的資料結構,基本特點就是先入先出,在事務處理等方面都要用到它,有的時候是帶有優先順序的佇列。當佇列存在併發訪問的時候,比如多執行緒情況下,就需要鎖機制來保證佇列中的同乙個元素不被多次獲取
乙個 mysql 表可以看作是乙個佇列,每一行為乙個元素。每次查詢得到滿足某個條件的最前面的一行,並將它從表中刪除或者改變它的狀態,使得下次查詢不會得到它。在沒有併發訪問的情況下,簡單地用 select 得到一行,再用update(或者delete)語句修改之,就可以實現。
複製** **如下:
select * from targets where status='c' limit 1;
update targets set status='d' where id='id';
如果有併發訪問,在select和update語句之間可能會存在其他地select查詢,導致同一行被取出多次。為了保證在併發情況下仍然能正常工作,一種思路是使用資料庫地鎖來防止,就像在多執行緒環境下所做地一樣。總之,要是的查詢和修改為乙個原子操作,不被其它的訪問干擾。mysql 5 支援儲存過程,可以用它來實現。
單條 update 語句應該原子操作的,可以利用這個特性來保證併發訪問情況下佇列的正常工作。每次取元素時,先用 update 修改符合條件的第一行,然後再得到該行。可惜 update 語句沒有返回值,重新用普通的select的話又很難找到剛被改過的那條記錄。
這裡用到乙個小技巧:在 update 時加上 id=last_insert_id(id),再用 select last_insert_id() 即可得到剛修改的那條記錄的id。還有乙個問題,當表中不存在符合條件的記錄,導致 update 失敗時,last_insert_id() 會保留原來地值不變,因而不能區分佇列中是否還有元素。
row_count() 返回上乙個語句影響的行數,把它作為 select 的乙個條件,可以幫助解決這個問題。
最後,支援併發訪問的完整解決方案為:
複製** **如下:
update targets set status='d', id=last_insert_id(id) where status='c' limit 1;
select * from targets where row_count()>0 and id=last_insert_id();
更新:在實現帶優先順序的佇列時這種方法有問題,帶有 order by ... 條件的 update 語句非常慢,例如:
複製** **如下:update targets set status='d' where status='c' order by schedule asc limit 1;
而單獨查詢和更新則是很快的:
複製** **如下:
select id from targets where status='c' order by schedule asc limit 1;
update targets set status='d' where id='id';
原來這是mysql的bug-12915,一年多以前提出來的,雖然關閉了,卻只解決了部分問題,尚不支援where,見mysql 5.0.15 的 changlog。無奈,上面這種巧妙的方法也沒有實用價值了。
最後採用了一種折衷方案,如下:
複製** **如下:
update targets, (select id from targets where status='c' and schedule
select * from targets where row_count()>0 and id=last_insert_id();
詳細出處參考:
mysql 佇列 實現併發讀
佇列是常用的資料結構,基本特點就是先入先出,在事務處理等方面都要用到它,有的時候是帶有優先順序的佇列。當佇列存在併發訪問的時候,比如多執行緒情況下,就需要鎖機制來保證佇列中的同乙個元素不被多次獲取 乙個 mysql 表可以看作是乙個佇列,每一行為乙個元素。每次查詢得到滿足某個條件的最前面的一行,並將...
mysql 佇列 實現併發讀
佇列是常用的資料結構,基本特點就是先入先出,在事務處理等方面都要用到它,有的時候是帶有優先順序的佇列。當佇列存在併發訪問的時候,比如多執行緒情況下,就需要鎖機制來保證佇列中的同乙個元素不被多次獲取 乙個 mysql 表可以看作是乙個佇列,每一行為乙個元素。每次查詢得到滿足某個條件的最前面的一行,並將...
go實現多佇列併發
1 場景描述 假設有乙個任務,分成a b c d四個步驟,四個步驟的耗時差別很大,且不同的任務可能是b的耗時最長,也有可能是d的耗時最長,步驟b和c依賴步驟a,步驟d依賴b和c。為了提高效能,故實現任務之間的併發。2 具體實現 用四個佇列分別完成任務中的每個步驟,佇列之間是併發的,佇列中可以順序執行...