2014-08-28 137 views
1

由於我正在處理大量的併發,所以我遇到了競爭條件。 我想結合這兩個mysql語句同時執行。同時選擇和更新 - 競賽條件

我需要選擇行和更新同一個...

SELECT id_file FROM filenames WHERE pending=1 LIMIT 1; 
UPDATE filenames SET pending=2 WHERE id_file=**id of select query**; 

另一種解決方案,以我遇到將執行UPDATE查詢,其中未決= 1,並以某種方式獲取競爭條件更新的行的ID,但我不確定這是甚至可能的?

感謝

+0

UPDATE filenames SET pending = 2 WHERE pending = 1 LIMIT 1 – cornelb 2014-08-28 22:54:46

+0

對不起,我應該指定,我仍然需要應用程序中的SELECT語句的id /結果。 – user2980769 2014-08-28 22:56:09

+0

如果你正在運行'UPDATE'語句,你還沒有'id_file'嗎? – user145400 2014-08-28 23:00:44

回答

1

您可以通過對錶執行只是一個UPDATE聲明避免了「跑」的條件,允許從該行確定該行修改,並隨後檢索列的值。

有一個「詭計」返回列的值,在你的情況下,id_file列的值剛剛更新的行。您可以使用LAST_INSERT_ID()函數(僅當列爲整數類型時)或MySQL 用戶定義變量

如果要檢索的列的值是整數,則可以使用LAST_INSERT_ID()函數(它支持BIGINT-64值)。

例如:

UPDATE filenames 
    SET pending = 2 
    , id_file = LAST_INSERT_ID(id_file) 
WHERE pending = 1 
LIMIT 1; 

繼UPDATE語句的成功執行,你要確認至少有一個行受到影響。 (如果任何行滿足WHERE,並聲明成功,我們知道,一個行會受到影響。然後你可以檢索值,在同一個會話:

SELECT LAST_INSERT_ID(); 

檢索的id_file列的值注意如果UPDATE處理多行,只有上一個由UPDATE處理的行將可用(但這對你來說不是問題,因爲有一個LIMIT 1子句)。

再次,您需要確保實際上更新了一行,然後才依靠返回的值10功能。


對於非整數列,可以以類似的方式使用MySQL用戶定義的變量,該列的值分配給一個用戶定義的變量,然後立即檢索存儲在用戶的值定義的變量。

-- initialize user-defined variable, to "clear" any previous value 
SELECT @id_file := NULL; 

-- save value of id_file column into user-defined variable 
UPDATE filenames 
    SET pending = 2 
    , id_file = (SELECT @id_file := id_file) 
WHERE pending = 1 
LIMIT 1; 

-- retrieve value stored in user-defined variable 
SELECT @id_file; 

請注意,該變量的值在會話中保留。如果UPDATE語句沒有找到任何滿足謂詞(WHERE子句)的行,那麼用戶定義變量的值將不受影響...因此,爲了確保您不會無意中獲得「舊」值,您可能需要首先使用NULL初始化該變量。

請注意,後續觸發的觸發器不會修改該用戶定義變量的值是很重要的。 (用戶定義的變量在當前會話中處於「範圍內」。)

也可以在觸發器中對用戶定義的變量進行賦值,但我不打算證明這一點,並且我會而不是建議您在觸發器中執行此操作。

1

處理併發性是transactions的基本功能之一。

包裝你的查詢到一個事務,並告訴DBMS,你需要的行不與FOR UPDATE之間改變:

BEGIN; 
SELECT id_file FROM filenames WHERE pending=1 LIMIT 1 FOR UPDATE; 
# do whatever you like 
UPDATE filenames SET pending=2 WHERE id_file=**id of select query**; 
COMMIT; 

你可以用4個mysqli_query調用執行這些語句,並做你想做的而不需要擔心數據庫的一致性。所選行保存直到您釋放它。