[英]Prevent two threads from selecting same row ibm db2
我有一種情況,我有多個(可能是數百個)線程重復執行相同的任務(如果您好奇,可以使用 java 調度執行程序)。 此任務需要選擇尚未處理的更改行(來自名為 change 的表)(已處理的更改在 am:n 連接表中跟蹤,稱為 process_change_rel 跟蹤進程 ID、記錄 ID 和狀態)處理它們,然后更新狀態。
我的問題是,防止來自同一進程的兩個線程選擇同一行的最佳方法是什么? 以下解決方案(用於更新以鎖定行)是否有效? 如果沒有,請提出一個可行的解決方案
Create table change(
—id , autogenerated pk
—other fields
)
Create table change_process_rel(
—change id (pk of change table)
—process id (pk of process table)
—status)
下面列出了我將使用的查詢
Select * from
change c
where c.id not in(select changeid from change_process_rel with cs) for update
請讓我知道這是否有效
您必須“鎖定”要以某種方式處理的行。 這種“鎖定”當然應該與最小的沖突/錯誤同時發生。
一種方法如下:
Create table change
(
id int not null generated always as identity
, v varchar(10)
) in userspace1;
insert into change (v) values '1', '2', '3';
Create table change_process_rel
(
id int not null
, pid int not null
, status int not null
) in userspace1;
create unique index change_process_rel1 on change_process_rel(id);
現在您應該能夠從多個並發會話中運行相同的語句:
SELECT ID
FROM NEW TABLE
(
insert into change_process_rel (id, pid, status)
select c.id, mon_get_application_handle(), 1
from change c
where not exists (select 1 from change_process_rel r where r.id = c.id)
fetch first 1 row only
with ur
);
每個這樣的語句都會向change_process_rel
表中插入 1 或 0 行,這里用作“鎖定”表。 返回change
對應的ID
,您可以在同一個事務中繼續處理對應的事件。
如果事務成功完成,那么插入到change_process_rel
表中的行被保存,因此,可以認為change
對應的id
被處理。 如果事務失敗,則來自change_process_rel
的相應“鎖定”行消失,並且該行稍后可能由該應用程序或另一個應用程序處理。
這種方法的問題是,當兩個表都變得足夠大時,這樣的子選擇可能不像以前那么快。
它需要將status
列放入change
表中。 不幸的是,Db2 for LUW 沒有SKIP LOCKED
功能,這可能有助於此類算法。
如果,比方說, status=0
是“未處理”,而status<>0
是一些正在處理/已處理的狀態,那么在設置這些DB2_EVALUNCOMMITTED
和DB2_SKIP*
注冊表變量並重新啟動實例之后,您可以“捕獲”下一個ID
用下面的語句處理。
SELECT ID
FROM NEW TABLE
(
update
(
select id, status
from change
where status=0
fetch first 1 row only
)
set status=1
);
獲得它后,您可以在與之前相同的事務中對該ID
進行進一步處理。
最好為性能創建一個索引:create index change1 on change(status); 並且可以將此表設置為 volatile 或定期收集該列的分布統計信息以及定期對表及其索引的統計信息。
請注意,此類注冊表變量設置具有全局影響,您應該牢記...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.