JDBC基础
作为基础知识的最后部分,我们来说一说结果集的处理,当然是说对一般结果集的处理.
, d4 s- v7 L6 I1 `9 F. C至于存储过程返回的多结果集,我们仍然放在高级应用中介绍.
H& F& B: I2 l V2 e G SQL语句如何执行的是查询操作,那就要返回一个ResultSet对象,要想把查询结果最后" m+ ?. m* u8 h. M) H! i% R
明白地显示给用户,必须对ResultSet进行处理.ResultSet返回的是一个表中符合条件的记录,对8 X; i, X9 P2 M6 K6 n7 o
ResultSet的处理要逐行处理,而对于每一行的列的处理,则可以按任意顺序(注意,这只是JDBC规) g; H4 z I& L5 q3 R. u- G
范的要求,有些JDBC实现时对于列的处理仍然要求用户按顺序处理,但这是极少数的).事实上,虽
: n# a" O* s1 J8 @; ?/ A然你可以在处理列的时候可以按任意顺序,但如果你按从左到右的顺序则可以得到较高的性能.
: i+ \ {( T, W& o, K3 {, G/ @$ n: H$ a5 Q& n, C
这儿从底层来讲解一下ResultSet对象,在任何介绍JDBC的书上你是不会获得这样的知( I4 b' N" e3 l$ Q0 }
识的,因为那是数据库厂商的事.ResultSet对象实际维护的是一个二维指针,第一维是指向当前
/ X7 k: ]6 E: r; {; K' J行,最初它指向的是结果集的第一行之前,所以如果要访问第一行,就要先next(),以后每一行都
1 F& n# v) ?& {# P2 X. |. g8 S要先next()才能访问,然后第二维的指针指向列,只要当你去rs.getXXX(列)时,才通过
; i, Y8 p. i! J7 Z8 s1 RConnection再去数据库把真实的数据取出来,否则没有什么机器能真的把要取的数据都放在内
7 M& | R2 P0 k- U; D: V2 l存中./ ^; X4 O) b" I# n9 P" [
所以,千万要记住,如果Connection已经关闭,那是不可能再从ResultSet中取到数据的.6 J' i2 w8 ?1 C! v* G
有很多人问我,我可不可以取到一个ResultSet把它写到Session中然后关闭Connection,这样就4 u! \6 C, K/ k4 C2 x
不要每次都连结了.我只能告诉你,你的想法非常好,但,是错误的!当然在javax.sql包中JDBC高$ Q9 N, ~- q% Z. P3 d D1 F
级应用中有CacheRow和WebCacheRow可以把结果集缓存下来,但那和我们自己开一个数据结构把: s* f" ?7 l, h( v/ A6 d: d
ResultSet的行集中所有值一次取出来保存起来没有什么两样., q6 _6 U+ R# `/ V. Z
访问行中的列,可以按字段名或索引来访问.下面是一个简单的检索结果的程序:
1 {5 W* ]! ^- g; \. a9 G
" H! b) G7 j0 F; @1 O$ S* m ResultSet rs = stmt.executeQuery(\"select a1,a2,a3 from table\");0 ?2 L1 ]9 }' \& @( {% h$ z! F
while(rs.next()){
" ]& G4 u4 k6 L) C. W- @ int i = rs.getInt(1);9 U& O- _5 s6 V9 w4 [' S
String a = rs.getString(\"a2\");+ x/ C+ r7 N; b, h# J ?3 ?- _
..............
" ]% x2 Z' p! [! } n }
, @0 e6 _; [: n" @" _
9 n! n8 |) w& p- d h 对于用来显示的结果集,用while来进行next()是最普通的,如果next()返回false,则
# c1 l( C+ W3 _- [" `说明已经没有可用的行了.但有时我们可能连一行都没有,而如果有记录又不知道是多少行,这时
H0 ^1 w$ a7 ^4 L如果要对有记录和没有记录进行不同的处理,应该用以下流程进行判断:
Q2 g5 }1 J4 Q/ M1 b$ _" C3 J* y/ D8 b8 H X
if(rs.next()){) y: u N+ D, |3 d) {
//因为已经先next()了,所经对记录应该用do{}while();来处理/ v' U8 `0 G; K8 y
do{
5 R. n$ o3 i% K int i = rs.getInt(1);
5 H$ r; U( M) ]- H3 ^ String a = rs.getString(\"a2\");
7 a3 V6 B) T% P& z }while(rs.next());. s! \& _9 U4 T# k2 x1 v
}
5 `1 L& K9 k( r' {. x esle{6 G0 {. V+ s# G u5 W7 d
System.out.println(\"没有取得符合条件的记录!\");
+ L; C" @0 O( O }
' n. d" m$ x. `# U9 \3 g
" h5 U/ w& D- n) |! o- n- D4 z 类型转换:, q8 ]6 j$ K/ L3 o( Z+ |
ResultSet的getXXX方法将努力把结果集中的SQL数据类型转换为JAVA的数据类型,事实
9 M3 o4 c& ^' Z大多数类型是可以转换的,但仍然有不少糊弄是不能转换的,如你不能将一个SQL的float转换成9 |, C6 \1 [! s/ I- x3 F2 h4 ]( D
JAVA的DATE,你无法将 VARCHAR \"我们\"转换成JAVA的Int.
- Z" h2 ]8 K& E) R. P6 l+ D9 I% f- m) X% g/ h
较大的值:: R( l. o4 z3 K2 N7 e( G
对于大于Statement中getMaxFieldSize返回值的值,用普通的getBytes()或getString()
4 ^$ s/ ~0 J- K% B+ f; {是不能读取的,好在JAVA提供了读取输入浪的方法,对于大对象,我们可以通过rs.getXXXStream()7 ` r3 U, j" X9 s* h
来得到一个InputStream,XXX的类型包括Ascii,Binay,Unicode.根据你存储的字段类型来使用不+ f& ?, h* u$ V$ m7 o' x. A- @/ g
同的流类型,一般来说,二进制文件用getBinayStream(),文本文件用getAsciiStyream(),对于( S) I$ q/ g/ D/ b, D
Unicode字符的文本文件用getUnicodeStream(),相对应的数据库字段类型应该为:Blob,Clob和
1 n6 j/ j8 x& h; e+ p5 U* k+ E% E; ~Nlob.
/ h* t# H) a# Z: _3 {/ v* C9 C6 v7 u& O0 T, N
获取结果集的信息:
& C/ q1 ]; [2 ]- G6 m: P$ m 大多数情况下编程人员对数据库结构是了解的,可以知道结果集中各列的情况,但有时并" Q; S! V4 U* } [2 a( O F
不知道结果集中有哪些列,是什么类型.这时可以通过getMetaData()来获取结果集的情况:' w2 z) d9 p5 k* B* U, E" I
7 C2 n# U7 ?. \6 x2 |. Z ResulSetMetaData rsmd = rs.getMetaData();
" D \; G% ^+ B" d% D rsmd.getColumnCount()返回列的个数.
( ]" Z1 K! w# w6 F: B5 _ getColumnLabel(int)返回该int所对应的列的显示标题3 e6 L9 A3 }3 L
getColumnName(int)返回该int所对应的列的在数据库中的名称.
6 U" F4 q+ H/ e+ T getColumnType(int)返回该int所对应的列的在数据库中的数据类型.% ~: O5 a# W: `) m3 _( \
getColumnTypeName(int)返回该int所对应的列的数据类型在数据源中的名称.
6 n) P/ [ N( k! t# L9 s isReadOnly(int)返回该int所对应的列是否只读.
' m. r+ U; r( o isNullable(int)返回该int所对应的列是否可以为空