0

我们有一个高事务性、高并发的 Java 系统来访问存储在 Oracle 11.g 实例上的数据。我们的系统部署在多个 Websphere 8.5 应用服务器上。对数据的并发访问由运行在不同线程中的不同事务进程执行。

考虑下表,其记录应按照规则处理:

  1. ID 只是一个序列号,表明首先创建了哪条记录。
  2. 没有要求 ID 是连续的数字,但可以确定 ID = 1 的记录是在 ID > 1 的记录之前插入的
  3. 必须按 ID 顺序处理具有相同 BUSINESS_ID 的记录(例如,对于 BUSINESS_ID=1,处理顺序必须是 ID = 1、2、4)
  4. 如果具有 BUSINESS_ID 的记录实际上正在由一个线程处理,则具有相同 BUSINESS_ID 的记录不应由不同的线程处理。
  5. 其他线程可以开始处理具有最小 ID 的记录,该记录具有当前未被任何其他线程处理的 BUSINESS_ID。
  6. 处理完一条记录后,该记录将从表中删除。

ID BUSINESS_ID

==============
1       1
2       1
3       2
4       1
5       3
6       3
7       2

要创建该测试数据,您可以运行以下命令:

create table test (id number, business_id number);
insert into test values (1, 1);
insert into test values (2, 1);
insert into test values (3, 2);
insert into test values (4, 1);
insert into test values (5, 3);
insert into test values (6, 3);
insert into test values (7, 2);
commit;

要模拟三个线程,您可以为每个线程打开一个单独的数据库会话。在这种情况下,处理流程可能如下所示:

  1. 线程A:找工作,得到记录ID=1(当前未处理的记录BUSINESS_ID的最小ID)这将锁定记录ID=1
  2. 线程 B:查找工作并获取记录 ID = 3(线程 A 当前正在处理的 BUSINESS_ID = 1 阻止线程 B 获取记录 ID = 2)
  3. 线程 C:查找工作并获取记录 ID = 5(BUSINESS_ID = 1 和 2 目前正在由线程 A 和 B 处理)
  4. 线程 A:完成工作并删除记录 ID =1 并提交工作。线程 A:找工作并获得记录 ID = 2
  5. 等等 ...

我的想法是使用 SELECT FOR UPDATE 来标记要处理的记录,并在工作完成时删除并提交所选记录。

使用存储过程实现此逻辑将起作用,但是我们的方法是将业务逻辑保持在 java 代码的中间层级别,而不是数据库级别。

您能看到一种仅通过运行 SQL 而不是在存储过程中实现它的方法来实现这一点吗?

因此,简而言之,我所追求的是 SELECT FOR UPDATE 记录具有最小 ID 且 BUSINESS_ID 不属于该表中任何其他锁定记录的记录。

先感谢您

4

0 回答 0