2015-06-21 53 views
1

我遇到了問題,無法選擇正確的解決方案。MySQL - 選擇後立即更新某個列

我有一個選擇查詢從表中選擇記錄。 這些記錄具有狀態列,如下所示。

SELECT id, <...>, status FROM table WHERE something 

現在,右後這個選擇我不得不UPDATE狀態欄。 如何避免競爭狀況?

我想實現的是一旦有人(會話)選擇了某個東西,這個東西不能被其他人選中,直到我沒有手動釋放它(例如使用狀態列)。

想法?

+0

使用過程返回結果並在選擇後添加更新某個標誌列。 – Mihai

+0

爲什麼選擇它? – Strawberry

+0

我選擇一位客戶並根據phone_number字段進行自動呼叫。問題在於,如果我已經向客戶發送了一個電話,我不希望這個客戶出現給另一個呼叫中心人員。現在發生的情況是,同一個客戶出現在兩個或更多的呼叫中心人員身上,這並不好。 – daryqsyro

回答

2

There是一些mysql文檔,thar可能會有趣的解決你的任務,不確定它是否適合你的需求,但它描述了正確的方式來做select然後更新。所描述的技術不會阻止其他會話讀取,但會阻止在事務結束之前寫入所選記錄。

它包含類似於您的問題的例子:

SELECT counter_field FROM child_codes FOR UPDATE; 
UPDATE child_codes SET counter_field = counter_field + 1; 

它要求你的表使用InnoDB引擎和程序中使用的交易。

如果您只需要鎖定很短的時間,即一個會話選擇鎖定行,更新它並在一個會話中釋放鎖定,則根本不需要字段狀態,只需使用select ... for updateselect ... lock in share mode,如果所有會話將使用這兩個與交易select... for update然後update修改,select ... with shared lock聯合交易 - 這將解決您的要求。

如果您需要長時間鎖定,請選擇並鎖定一個會話,然後在另一個會話中更新並釋放,然後您使用某個存儲來保持鎖定狀態,並且所有會話都應按如下所述使用:select ... for update並設置狀態和狀態所有者在一個會話中,然後在另一個會話中select for update檢查狀態和所有者,更新和刪除狀態 - 用於更新方案,用於讀取方案:select ... with shared lock檢查狀態。

1

你可以做一些準備。將一列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並設置sessionIdNULL(釋放行)和status,以反映其新的地位。

此外,您應該在會話關閉時釋放行(使用與上述相同的過程)。

+0

難道沒有美麗和方便的方法嗎?我需要的只是讀取鎖定最後一個選擇語句中選中的行,並在需要時釋放它。 – daryqsyro