Db2
如何鎖定行以在 DB2 中讀取/更新?
我正在嘗試解決我的應用程序中的競爭條件。
我有一個用作工作隊列和許多執行緒並讀取/更新它的表。以下查詢從應用程序執行。首先,它讀取可用作業的 ID,然後保留它們並獲取資訊。
SELECT ID FROM JOBS WHERE LOCKED_BY IS NULL LIMIT 5; --Check available jobs UPDATE JOBS LOCKED_BY = 'Thread#1' WHERE ID IN (?); --Lock jobs SELECT * FROM JOBS WHERE ID IN(?); --Get info about jobs to process
當多個執行緒同時進入此表時會出現問題。如果
'Thread#2'
在'Thread#1'
執行UPDATE
. 導致相同的作業執行兩次。我通過將查詢包裝在以下內容中找到了解決方案:
LOCK TABLE JOBS; --Queries from above COMIT;
這可以正常工作並防止競爭條件,但它有點極端,因為執行緒必須等待彼此完成。
如何確保只能對來自以下查詢的記錄進行鎖定?
SELECT ID FROM JOBS WHERE LOCKED_BY IS NULL LIMIT 5;
這是在 AS400 DB2 數據庫上,現在是 LUW
你為什麼用桌子?IBM i 提供了一個本地數據隊列對象…
如果您的應用程序以不提供對本機對象的直接訪問的語言在平台外執行,您總是可以在 I 上建構儲存過程或使用者定義的函式來提供對數據隊列的訪問。
話雖如此,對於任何 RDBMS,您的問題的答案都是相同的,請使用隔離級別。
在您的情況下,您想使用Read Stability
與級別 RR 一樣,級別讀取穩定性 (RS) 確保:
在工作單元完成之前,使用不同承諾定義的其他啟動組不會更改在工作單元期間讀取的任何行。1 由另一個啟動組使用不同的送出定義更改的任何行(或目前使用 UPDATE 行鎖鎖定的行)在送出之前無法讀取。
只需添加
WITH RS
到您的陳述…SELECT ID FROM JOBS WHERE LOCKED_BY IS NULL WITH RS LIMIT 5 UPDATE JOBS LOCKED_BY = 'Thread#1' WHERE ID IN (?) WITH RS COMMIT
第一條語句將鎖定(最多)5 行..直到
COMMIT
完成。請注意,如果還沒有記錄該表,則需要記錄該表。