【发布时间】:2018-12-12 17:44:39
【问题描述】:
我们正在尝试实施一个需要我们这样做的解决方案,
频繁轮询控制表以查询未处理的事务
一旦我们从步骤 1 中提取交易标识符,我们就必须查询详细信息。这一步是现有功能,只是我们通过在第一步中加入控制表来进行全扫描。
当有卷时,现有解决方案开始减慢处理速度。因此,我们决定从状态表中提取未处理的事务并进行 PK 查找以查询详细信息。
我知道这不是一个理想的解决方案,如适配器、CDC 或在视图中表达完整的细节。我们受到限制,因为产品合同禁止我们在源模式或源 Oracle 实例中的任何位置创建任何类型的对象,这让我们轮询表,并且此解决方案需要可扩展且接近实时(5 秒延迟) .
DDL:
CREATE TABLE "CONTROL_TABLE"
(
"REF_NO" VARCHAR2(16 CHAR),
"BRANCH" VARCHAR2(3 CHAR),
"INIT_DATE" DATE,
"STATUS" VARCHAR2(1 CHAR),
CONSTRAINT "CONST_CONTROL_TABLE" PRIMARY KEY ("REF_NO")
)
以下是我作为 POC 尝试过的,执行以下块,
1. 创建一个块来运行 SELECT for UPDATE,如下所示。在下面的块中,我选择使用“SKIP LOCKED”进行更新并更新游标范围内的记录。
DECLARE
CURSOR tCURSOR IS
SELECT REF_NO FROM CONTROL_TABLE
WHERE STATUS = 'U' FOR UPDATE OF STATUS SKIP LOCKED;
BEGIN
FOR tCURSORREC IN tCURSOR LOOP
UPDATE CONTROL_TABLE SET STATUS='W' WHERE STATUS='U';
END LOOP;
COMMIT;
END;
上面的块工作得很好,我已经通过随机插入新记录和更新来自不同客户端会话的状态进行了测试。我的问题是我想让光标返回到 Java 客户端进行下游处理。参考之前的一篇文章,其中只有一个 SELECT 查询将游标绑定变量返回到 Java。非常感谢任何有用的指针。 Execute anonymous pl/sql block and get resultset in java
运行该块的Java sn-p,
public static void main(String args[]) throws Exception
{
final Connection c = DriverManager.getConnection("jdbc:oracle:thin:<<service_name>>:8888:<<schema>>", "user", "passwd");
String plsql = "declare\r\n" +
" cursor tCursor is\r\n" +
" select ref_no from CONTROL_TABLE \r\n" +
" where status = 'U' for update of REF_NO,STATUS skip locked;\r\n" +
"begin\r\n" +
" for tCursorRec in tCursor loop\r\n" +
" update CONTROL_TABLE set status='W' where status ='U'; \r\n" +
" end loop;\r\n" +
" commit; \r\n" +
"? := tCursor" +
"end;";
CallableStatement cs = c.prepareCall(plsql);
cs.registerOutParameter(1, OracleTypes.CURSOR);
cs.execute();
ResultSet cursorResultSet = (ResultSet) cs.getObject(1);
while (cursorResultSet.next ())
{
System.out.println (cursorResultSet.getString(1));
}
cs.close();
c.close();
Exception:Exception in thread "main" java.sql.SQLException: ORA-06550:
line 10, column 8:
PLS-00382: expression is of wrong type
ORA-06550: line 10, column 1:
【问题讨论】:
-
PL/SQL 显式游标与 ref 游标不同,后者正是 Java 端所寻找的。但是你有一个更深层次的问题——除了每次在循环中更新表中的所有“U”行之外,无论你是否锁定它们——因为当你尝试分配游标时,游标已经用尽了;而且您无法重新打开它,因为您更改了数据,因此它找不到任何东西。您确定要在循环中更新并提交(释放锁),而不是进行进一步处理吗?无论哪种方式,您都希望将 ref 编号列表返回给 Java,对吗?
-
Alex,在 Java 中获得 REF_NO 是我的目标。另一个线程也不应该提取相同的参考编号。这就是选择 FOR ... UPDATE 的原因。谢谢..