我遇到了問題,無法選擇正確的解決方案。MySQL - 選擇後立即更新某個列
我有一個選擇查詢從表中選擇記錄。 這些記錄具有狀態列,如下所示。
SELECT id, <...>, status FROM table WHERE something
現在,右後這個選擇我不得不UPDATE狀態欄。 如何避免競爭狀況?
我想實現的是一旦有人(會話)選擇了某個東西,這個東西不能被其他人選中,直到我沒有手動釋放它(例如使用狀態列)。
想法?
我遇到了問題,無法選擇正確的解決方案。MySQL - 選擇後立即更新某個列
我有一個選擇查詢從表中選擇記錄。 這些記錄具有狀態列,如下所示。
SELECT id, <...>, status FROM table WHERE something
現在,右後這個選擇我不得不UPDATE狀態欄。 如何避免競爭狀況?
我想實現的是一旦有人(會話)選擇了某個東西,這個東西不能被其他人選中,直到我沒有手動釋放它(例如使用狀態列)。
想法?
There是一些mysql文檔,thar可能會有趣的解決你的任務,不確定它是否適合你的需求,但它描述了正確的方式來做select然後更新。所描述的技術不會阻止其他會話讀取,但會阻止在事務結束之前寫入所選記錄。
它包含類似於您的問題的例子:
SELECT counter_field FROM child_codes FOR UPDATE;
UPDATE child_codes SET counter_field = counter_field + 1;
它要求你的表使用InnoDB引擎和程序中使用的交易。
如果您只需要鎖定很短的時間,即一個會話選擇鎖定行,更新它並在一個會話中釋放鎖定,則根本不需要字段狀態,只需使用select ... for update
和select ... lock in share mode
,如果所有會話將使用這兩個與交易select... for update
然後update
修改,select ... with shared lock
聯合交易 - 這將解決您的要求。
如果您需要長時間鎖定,請選擇並鎖定一個會話,然後在另一個會話中更新並釋放,然後您使用某個存儲來保持鎖定狀態,並且所有會話都應按如下所述使用:select ... for update
並設置狀態和狀態所有者在一個會話中,然後在另一個會話中select for update
檢查狀態和所有者,更新和刪除狀態 - 用於更新方案,用於讀取方案:select ... with shared lock
檢查狀態。
你可以做一些準備。將一列sessionId
添加到您的表中。它必須是NULL
-able,它將包含獲取該行的會話的唯一ID。還要在這個新列上添加一個索引;我們將使用該列來搜索表中的行。
ALTER TABLE `tbl`
ADD COLUMN `sessionId` CHAR(32) DEFAULT NULL,
ADD INDEX `sessionId`(`sessionId`)
當一個會話需要獲取一些行(基於某些條件)運行:
UPDATE `tbl`
SET `sessionId` = 'aaa'
WHERE `sessionId` IS NULL
AND ...
LIMIT bbb
更換aaa
與當前會話ID和...
你需要選擇正確的行的條件。將bbb
替換爲您需要獲取的行數。如果需要按特定順序處理行(如果其中一些具有比其他更高的優先級),則添加ORDER BY
子句。您還可以在UPDATE
子句中添加status = ...
以更改所獲取行的狀態(至pending
f.e.),讓其他代碼實例知道這些行現在處理完畢。
上面的查詢獲取一些行。接下來,運行:
SELECT *
FROM `tbl`
WHERE `sessionId` = 'aaa'
此查詢獲取要在客戶端代碼中處理的獲取行。
後每行處理,你要麼DELETE
行或UPDATE
並設置sessionId
到NULL
(釋放行)和status
,以反映其新的地位。
此外,您應該在會話關閉時釋放行(使用與上述相同的過程)。
難道沒有美麗和方便的方法嗎?我需要的只是讀取鎖定最後一個選擇語句中選中的行,並在需要時釋放它。 – daryqsyro
使用過程返回結果並在選擇後添加更新某個標誌列。 – Mihai
爲什麼選擇它? – Strawberry
我選擇一位客戶並根據phone_number字段進行自動呼叫。問題在於,如果我已經向客戶發送了一個電話,我不希望這個客戶出現給另一個呼叫中心人員。現在發生的情況是,同一個客戶出現在兩個或更多的呼叫中心人員身上,這並不好。 – daryqsyro