|
我有一个像这样构造的PL / SQL查询:
# K6 C! k$ [& b7 g1 k eDECLARE$ _6 T+ s& f5 T
a NUMBER;
1 H b" V9 X+ |2 J# |' L2 BB NUMBER;$ ^, P5 {: v; s+ @; k: u. l
CURSOR cursor
4 ]. |# y5 C2 M# RIS
2 T0 T: I* U' M* b( ? ( SOME SELECT QUERY);! R C5 e& p0 P, M9 O8 H9 _
BEGIN |' L( h- c# H. x1 T. p, [
OPEN cursor;
9 M" [& h2 O9 c; V LOOP
% A6 d% w+ } H; R* s2 u1 p SOME STUFF;
F1 Z0 q& P1 _) o END LOOP;! @; h8 r2 Y3 P/ r, a
CLOSE cursor;* c F- G( p3 h0 W9 q
END* ?2 H9 D- S4 J5 e) z
如何使用jdbc从Java代码运行此查询并获取结果集?我尝试不使用游标来运行查询,并且其运行正常。我想不出一种在Java代码中执行此操作的方法。如果我直接将查询运行到oracle客户端上,它将正常工作。因此查询没有问题。
+ z3 P7 s8 e4 Z# @$ i: X& ]PS我不想将代码存储为存储过程,并由于某些限制而调用它。, j( p3 z4 i* n* ~1 x0 k* Y
" O4 x0 A% {. e0 R. {
解决方案:6 H0 S! B- i6 u
! k0 @$ L3 [( }' A' k* ]' A1 A/ \5 s* n: l
: n; l# V2 g# l0 Z- |. o 这是不可能的。您无法从匿名PL / SQL块返回结果集(因此无法从JDBC获取结果集)。6 A) @; r3 q3 m% {" W) C6 A- Z
您将需要直接从JDBC运行select。
' @+ O8 } C+ F( ?% J$ ~唯一的,非常丑陋的解决方法是使用dbms_output.put_line()和读取之后的内容。但这是一个非常丑陋的技巧,直接在JDBC中处理SELECT查询的结果要好得多。
0 \$ S$ M1 u* y
- g4 l# M4 \% J1 V$ ^编辑14 \4 l3 ~+ f1 M
这是一个使用dbms_output的小例子:+ a1 h# s2 R, S7 X L
Connection con = ....;5 l$ P) P% S8 ?1 L( i2 c( e% ]
// turn on support for dbms_output' N+ }% c5 {, A( ^0 I4 U$ \8 o
CallableStatement cstmt = con.prepareCall("{call dbms_output.enable(32000) }");
6 W6 F4 f1 e l7 i: L; hcstmt.execute();
" H& f3 h' p$ a' D// run your PL/SQL block/ h4 X- Q2 v# b" \* s2 ?3 E J) A
Statement stmt = con.createStatement();
7 A9 H5 x# p4 o3 L% O2 v0 IString sql =
D: C$ U8 q" ^% M |1 ~/ o w: n "declare \n" +
! q3 M' B, F8 k9 w% Q" @ " a number; \n" +
! X! z4 R/ K6 d' y " cursor c1 is select id from foo; \n" +
( z5 Z" I- G0 c2 C "begin \n" +9 J( B m% I }: f, K9 a
" open c1; \n" +4 _0 [$ j, z" S3 Y' ~& W
" loop \n" +
! M! k0 h% p- x" o7 P9 \/ s: R " fetch c1 into a; \n" +
7 c1 `% Y7 W K) O; @ X " exit when c1%notfound; \n" +3 m Q! U1 Y. ?+ x; V0 Q! A
" dbms_output.put_line('ID: '||to_char(a)); \n" +. r4 h8 |% j0 W1 m
" end loop; \n" +
0 F" ?) }2 T2 w9 J "end;";
* h X7 `3 f- f, V' W% n$ Kstmt.execute(sql);- u( H" |8 [; D7 J
// retrieve the messages written with dbms_output
1 m- m' V+ ~) e3 K( A: Mcstmt = con.prepareCall("{call dbms_output.get_line(?,?)}");* x/ a! ?5 m) \, O
cstmt.registerOutParameter(1,java.sql.Types.VARCHAR);; R7 D0 } V* |
cstmt.registerOutParameter(2,java.sql.Types.NUMERIC);5 H- n4 A2 }4 m" U
int status = 0;/ \) F0 n& ]. q
while (status == 0)
, C2 i7 }4 U/ h{
' r& S9 s) B1 X# N% m3 U cstmt.execute();
* z3 c" R0 Y% `( D r String line = cstmt.getString(1);
: Q3 k: a* ^6 R4 H8 Y status = cstmt.getInt(2);
1 J4 m1 ^" L7 P% ] if (line != null && status == 0)
0 j! r' h: a3 V% [ {
- J8 G, k% R# q. u- q1 @- p System.out.println(line);
: F1 v" X, u" h) B+ h g- }# b! d }
0 z0 M- k* i: W" P1 h}# p9 R% ?* K& Q0 c
1 l1 ?- i% A/ _8 w编辑2(对于评论来说这太长了)
% \2 i9 M, I# q+ M嵌套循环来检索数据几乎总是一个坏主意。如果您发现自己在做这样的事情:
9 [% w! p) [0 L# G- sbegin1 [7 f7 @. E2 F' P9 f! P9 r
for data_1 in (select id from foo_1) loop
! m( N3 s/ F# j* `) t! G/ a+ m dbms_output.put_line(to_char(data_1.id));: b, }; t9 i# o- F* q# U' T
for data_2 in (select f2.col1, f2.col2 from foo_2 f2 where f2.id = data_1.id) loop
8 o6 p7 B9 Y# j ... do something else0 i) r# l( s4 v/ r* `/ X9 Z
end loop;
- g/ h8 o! y0 l! O t7 A6 K4 H end loop;
& V7 y# G2 W2 l$ \3 G; H+ Gend;* D- b% S9 ~5 j2 A/ } h$ W1 F/ D
/
" |' p' w3 [7 U) D; t这样做会更加高效:
N% w) `9 s$ m1 t; z3 a, j3 d obegin
. v/ x8 d, c; C1 Y' P for data_1 in (select f2.col1, f2.col2 from foo_2 f28 T$ l! i/ i2 t- c2 e6 f
where f2.id in (select f1.id from foo_1 f1)) loop
" N$ F4 j4 A& P# ] _& n ... do something
/ x$ j9 g$ s& j end loop;/ }+ G3 t. P9 F+ |0 H+ i0 k( @
end;' E- T0 F" Z2 V4 r- s) {+ k' v
/ x3 I" C8 z: ^' W3 _: f, m
可以使用类似以下的方法来处理此过程,而不会在JDBC中占用过多的内存:1 z% e% a9 Z/ ]9 S
String sql = "select f2.col1, f2.col2 from foo_2 f2 where f2.id in (select f1.id from foo_1 f1)";
, V& f8 Y, i1 A7 t4 c; cStatement stmt = connection.createStatement();
1 Z. ]( D* Q4 ^8 eResultSet rs = stmt.executeQuery(sql);
1 _2 {9 M1 R0 {/ S7 L) v* R1 Owhile (rs.next())
4 K" @! Z2 H2 h( x% J/ y{
& x8 o1 S# q$ @9 Y, f2 O9 Y String col1_value = rs.getString(1);+ C1 H. O5 `/ G2 `" Y
int col2_value = rs.getInt(2);+ ]* P( z% R. @; M* s
... do something6 Y7 q4 c8 L5 v" e
}. @/ d- S2 N/ o* g
上面的代码即使处理数十亿行,也只会在内存中保留一行。准确地说:JDBC驱动程序实际上将预取多行。默认值为10,可以更改。但是即使那样,您也不会占用过多的内存。 |
|