如何使用 JDBC 在 Java 应用程序中获取 Oracle 的 dbms_output.get_lines
的输出而不在数据库中创建额外的对象?
最佳答案
I've also blogged about this issue here .下面是一个片段,说明了如何做到这一点:
try (CallableStatement call = c.prepareCall(
"declare "
+ " num integer := 1000;" // Adapt this as needed
+ "begin "
// You have to enable buffering any server output that you may want to fetch
+ " dbms_output.enable();"
// This might as well be a call to third-party stored procedures, etc., whose
// output you want to capture
+ " dbms_output.put_line('abc');"
+ " dbms_output.put_line('hello');"
+ " dbms_output.put_line('so cool');"
// This is again your call here to capture the output up until now.
// The below fetching the PL/SQL TABLE type into a SQL cursor works with Oracle 12c.
// In an 11g version, you'd need an auxiliary SQL TABLE type
+ " dbms_output.get_lines(?, num);"
// Don't forget this or the buffer will overflow eventually
+ " dbms_output.disable();"
+ "end;"
)) {
call.registerOutParameter(1, Types.ARRAY, "DBMSOUTPUT_LINESARRAY");
call.execute();
Array array = null;
try {
array = call.getArray(1);
System.out.println(Arrays.asList((Object[]) array.getArray()));
}
finally {
if (array != null)
array.free();
}
}
以上将打印:
[abc, hello, so cool, null]
请注意,ENABLE
/DISABLE
设置是一个连接范围的设置,因此您也可以通过多个 JDBC 语句执行此操作:
try (Connection c = DriverManager.getConnection(url, properties);
Statement s = c.createStatement()) {
try {
s.executeUpdate("begin dbms_output.enable(); end;");
s.executeUpdate("begin dbms_output.put_line('abc'); end;");
s.executeUpdate("begin dbms_output.put_line('hello'); end;");
s.executeUpdate("begin dbms_output.put_line('so cool'); end;");
try (CallableStatement call = c.prepareCall(
"declare "
+ " num integer := 1000;"
+ "begin "
+ " dbms_output.get_lines(?, num);"
+ "end;"
)) {
call.registerOutParameter(1, Types.ARRAY, "DBMSOUTPUT_LINESARRAY");
call.execute();
Array array = null;
try {
array = call.getArray(1);
System.out.println(Arrays.asList((Object[]) array.getArray()));
}
finally {
if (array != null)
array.free();
}
}
}
finally {
s.executeUpdate("begin dbms_output.disable(); end;");
}
}
另请注意,这将获取最多 1000 行的固定大小。如果您需要更多行,您可能需要在 PL/SQL 中循环或轮询数据库。
使用 jOOQ 来做到这一点
请注意,如果您是 jOOQ用户,您可以根据查询自动获取服务器输出:
DSLContext ctx = DSL.using(c,
new Settings().withFetchServerOutputSize(10));
然后您应该看到 FetchServerOutputListener
的一些 DEBUG
日志输出,例如
DEBUG [LoggerListener ] Executing query : begin my_procedure(1, 2); end;
DEBUG [FetchServerOutputListener] <output here>
除了上述DEBUG
日志之外,您还将在ExecuteContext::serverOutput
中获得信息。
This is also mentioned in the linked blog post
关于调用 DBMS_OUTPUT.GET_LINE
的注意事项
以前,有一个现已删除的答案建议单独调用 DBMS_OUTPUT.GET_LINE
,一次返回一行。我已经对方法进行了基准测试,将它与 DBMS_OUTPUT.GET_LINES
进行了比较,差异非常大——从 JDBC 调用时速度最多慢 30 倍(即使从PL/SQL)。
因此,使用 DBMS_OUTPUT.GET_LINES
的批量数据传输方法绝对值得。这是基准测试的链接:
关于java - 使用 JDBC 从 dbms_output.get_lines 获取输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47830370/