【问题标题】:Prevent two threads from selecting same row ibm db2防止两个线程选择同一行 ibm db2
【发布时间】:2020-02-11 23:23:28
【问题描述】:

我有一个情况,我有多个(可能数百个)线程重复相同的任务(如果你好奇,使用 java 调度执行器)。此任务需要选择尚未处理的更改行(从名为 change 的表中)(已处理的更改在名为 process_change_rel 的 m:n 连接表中跟踪,该表跟踪进程 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

请告诉我这是否可行

【问题讨论】:

  • 什么是 Db2 版本和平台?
  • 我正在使用 db2 luw 11
  • 试试 CS 隔离级别?
  • 你为什么选择 ur?

标签: db2 race-condition db2-luw transaction-isolation rowlocking


【解决方案1】:

您必须以某种方式“锁定”您要处理的行。这样的“锁定”当然应该与最小的冲突/错误同时发生。
一种方法如下:

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 的相应“锁定”行将消失,此行可能稍后由该应用程序或其他应用程序处理。
这种方法的问题是,当两个表都变得足够大时,这样的子选择可能不会像以前那样快速。

另一种方法是使用Evaluate uncommitted data through lock deferral

需要将status 列放入change 表中。 不幸的是,Db2 for LUW 没有 SKIP LOCKED 功能,这可能有助于此类算法。
如果,假设status=0 是“未处理”,而status<>0 是一些处理/处理状态,那么在设置这些DB2_EVALUNCOMMITTEDDB2_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
最好为性能创建一个索引: 在 change(status) 上创建索引 change1; 并且可以将此表设置为 volatile 或收集此列的分布统计信息,以及定期对表及其索引进行定期统计。
请注意,这样的注册表变量设置具有全局效果,您应该牢记...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-24
    • 2021-04-03
    • 1970-01-01
    • 2019-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多