|
下面的代码演示了一种方法用来确认已访问调用方法execute所产生的全部结果集和更新计数:
stmt.execute(queryStringWithUnknownResults); while(true){ introwCount=stmt.getUpdateCount(); if(rowCount>0){//它是更新计数 System.out.println("Rows changed="+count); stmt.getMoreResults(); continue; } if(rowCount==0){//DDL命令或0个更新 System.out.println("No rows changed or statement was DDL command"); stmt.getMoreResults(); continue; } //执行到这里,证明有一个结果集 //或没有其它结果 ResultSet rs=stmt.getResultSet(); if(rs!=null){ ...//使用元数据获得关于结果集列的信息 while(rs.next()){ ...//处理结果 stmt.getMoreResults(); continue; } break;//没有其它结果 如何获得SQL语句的执行结果?
ResultSet包含符合SQL语句中条件的所有行,并且它通过一套get方法(这些get方法可以访问当前行中的不同列)提供了对这些行中数据的访问。ResultSet.next方法用于移动到ResultSet中的下一行,使下一行成为当前行。
下面的代码段是执行SQL语句的示例。该SQL语句将返回行集合,其中列1为int,列2为String,而列3则为字节数组:
Java.sql.Statementstmt=conn.createStatement(); ResultSet r=stmt.executeQuery("SELECT a,b,c FROM Table1"); while(r.next()){ //打印当前行的值。 Int i=r.getInt("a"); String s=r.getString("b"); Float f=r.getFloat("c"); System.out.println("ROW="+i+" "+s+" "+f); }
1. 行和光标
ResultSet维护指向其当前数据行的光标。每调用一次next方法,光标向下移动一行。
最初它位于第一行之前,因此第一次调用next将把光标置于第一行上,使它成为当前行。随着每次调用next导致光标向下移动一行,按照从上至下的次序获取ResultSet行。
在ResultSet对象或其父辈Statement对象关闭之前,光标一直保持有效。在SQL中,结果表的光标是有名字的。如果数据库允许定位更新或定位删除,则需要将光标的名字作为参数提供给更新或删除命令。可通过调用方法getCursorName获得光标名。
DatabaseMetaData.supportsPositionedDelete和supportsPositionedUpdate方法来检查特定连接是否支持这些操作。当DBMS支持定位更新和删除操作时,DBMS/驱动程序必须确保适当锁定选定行,以使定位更新不会导致更新异常或其它并发问题。
2. 列
方法getXXX提供了获取当前行中某列值的途径。在每一行内,可按任何次序获取列值。但为了保证可移植性,应该从左至右获取列值,并且一次性地读取列值。
列名或列号可用于标识要从中获取数据的列。例如,如果ResultSet对象rs的第二列名为"title",并将值存储为字符串,则下列任一代码将获取存储在该列中的值:
String s=rs.getString("title"); String s=rs.getString(2);
注意列是从左至右编号的,并且从列1开始。同时,用作getXXX方法的输入的列名不区分大小写。
提供使用列名这个选项的目的是为了让在查询中指定列名的用户可使用相同的名字作为getXXX方法的参数。另一方面,如果select语句未指定列名(例如在"select * from table1"中或列是导出的时),则应该使用列号。这些情况下,用户将无法确切知道列名。
有些情况下,SQL查询返回的结果集中可能有多个列具有相同的名字。如果列名用作getXXX方法的参数,则getXXX将返回第一个匹配列名的值。因而,如果多个列具有相同的名字,则需要使用列索引来确保检索了正确的列值。这时,使用列号效率要稍微高一些。
关于ResultSet中列的信息,可通过调用方法ResultSet.getMetaData得到。返回的ResultSetMetaData对象将给出其ResultSet对象各列的编号、类型和属性。
如果列名已知,但不知其索引,则可用方法findColumn得到其列号。
3. 数据类型和转换
对于getXXX方法,JDBC驱动程序试图将基本数据转换成指定Java类型,
然后返回适合的Java值。例如,如果getXXX方法为getString,而基本数据库中数据类型为VARCHAR,则JDBC驱动程序将把VARCHAR转换成JavaString。getString的返回值将为JavaString对象。
4. 对非常大的行值使用流 ResultSet可以获取任意大的LONGVARBINARY或LONGVARCHAR数据。方法getBytes和getString将数据返回为大的块(最大为Statement.getMaxFieldSize的返回值)。但是,以较小的固定块获取非常大的数据可能会更方便,而这可通过让ResultSet类返回Java.io.Input流来完成。从该流中可分块读取数据。注意:必须立即访问这些流,因为在下一次对ResultSet调用getXXX时它们将自动关闭(这是由于基本实现对大块数据访问有限制)。
JDBCAPI具有三个获取流的方法,分别具有不同的返回值:
?getBinaryStream:返回只提供数据库原字节而不进行任何转换的流。
?getAsciiStream返回提供单字节ASCII字符的流。
?getUnicodeStream返回提供双字节Unicode字符的流。
注意:它不同于Java流,后者返回无类型字节并可(例如)通用于ASCII和Unicode字符。下列代码演示了getAsciiStream的用法:
Java.sql.Statementstmt=con.createStatement(); ResultSet r=stmt.executeQuery("SELECT x FROM Table2"); //现在以4K块大小获取列1结果: byte buff=newbyte[4096]; while(r.next()){ Java.io.InputStream fin=r.getAsciiStream(1); for(;;){ intsize=fin.read(buff); if(size==-1){//到达流末尾 break; } //将新填充的缓冲区发送到ASCII输出流: output.write(buff,0,size); } }
5. NULL结果值
要确定给定结果值是否是JDBC NULL,必须先读取该列,然后使用ResultSet.wasNull 方法检查该次读取是否返回JDBC NULL。
当使用ResultSet.getXXX方法读取JDBC NULL时,方法wasNull将返回下列值之一:
(1)Javanull值
对于返回Java对象的getXXX方法(例如getString、getBigDecimal、getBytes、getDate、getTime、getTimestamp、getAsciiStream、getUnicodeStream、getBinaryStream、getObject等)。
(2)零值:对于getByte、getShort、getInt、getLong、getFloat和getDouble。
(3)false值:对于getBoolean。
6. 可选结果集或多结果集
通常使用executeQuery(它返回单个ResultSet)或executeUpdate(它可用于任何数据库修改语句,并返回更新行数)可执行SQL语句。但有些情况下,应用程序在执行语句之前不知道该语句是否返回结果集。此外,有些已存储过程可能返回几个不同的结果集和/或更新计数。
为了适应这些情况,JDBC提供了一种机制,允许应用程序执行语句,然后处理由结果集和更新计数组成的任意集合。这种机制的原理是首先调用一个完全通用的execute方法,然后调用另外三个方法,getResultSet、getUpdateCount和getMoreResults。这些方法允许应用程序一次一个地研究语句结果,并确定给定结果是ResultSet还是更新计数。
用户不必关闭ResultSet;当产生它的Statement关闭、重新执行或用于从多结果序列中获取下一个结果时,该ResultSet将被Statement自动关闭。 基于JDBC有哪些数据库通用访问方法?
1. 通用数据库Bean设计
本实例中对数据库连接和执行SQL语句等通用数据库操作进行了封装,通过实现DBConnBean和DBQueryBean两个JavaBean来完成上述功能。其中DBConnBean负责Java应用程序和数据库的连接;DBQueryBean提供了一组执行标准SQL的功能,可以实现标准SQL完成的所有功能。其功能代码分别如下所示:
① DBConnBean.Java的源代码如下所示:
package dbaccess; import Java.sql.*; import Java.util.*; import Java.io.*; public class DBConnBean implements Serializable{
private String DBDriver = "sun.jdbc.odbc.JdbcOdbcDriver"; private String DBHost = "127.0.0.1"; private String DBName = "demo"; private String conp = "jdbc:odbc:db_demo"; private String username = ""; private String password = ""; private boolean xdebug = true;
public Connection con = null;
public String sql = null;
Statement stmt = null; public ResultSet result = null; private int affectedRows = 0;
public DBConnBean() { xdebug = true; con = null; sql = null; } public Connection Connect() throws Exception { String msg = null; try { Class.forName(DBDriver).newInstance(); } catch(Exception e) { msg = "加载数据库驱动失败"; if (xdebug) msg += "(驱动'"+DBDriver+"')"; throw new Exception(msg); } try { String conStr = conp; con = DriverManager.getConnection(conStr,username,password); } catch(SQLException e) { msg = "!!数据库连接失败"; if (xdebug) { msg += "(错误信息='" + e.getMessage()+"' SQL状态值='" + e.getSQLState()+"' 错误代码='" + e.getErrorCode()+"')"; } throw new Exception(msg); } return con; } protected void finalize() throws Throwable { super.finalize(); if (stmt != null) stmt.close(); if (result != null) result.close(); } //最近一次对数据库查询受影响的行数 public int getAffectedRows() { return affectedRows; } public Connection getCon() { return con; } public String getConp() { return conp; } public String getDBDriver() { return DBDriver; } public String getDBName() { return DBName; } public boolean getDebug() { return xdebug; } public String getPassword() { return password; } public ResultSet getResult() { return result; } public String getSql() { return sql; } public String getUsername() { return username; } public void over() throws Throwable { finalize(); } public ResultSet query() throws Exception { result = null; affectedRows = 0; if (con == null) Connect(); if (stmt == null) stmt = con.createStatement(); if (sql.substring(0,6).equalsIgnoreCase("select")) { result = stmt.executeQuery(sql); } else { affectedRows = stmt.executeUpdate(sql); } return result; } public ResultSet query(String s) throws Exception { sql = s; return query(); } public void setDBDriver(String s) { DBDriver = s; } public void setDebug(boolean b) { xdebug = b; } public void setgetConp(String s) { conp = s; } public void setgetDBName(String s) { DBName = s; } public void setgetUsername(String s) { username = s; } public void setPassword(String s) { password = s; } public void setSql(String s) { sql = s; } } ② DBQueryBean.Java的源代码如下所示: package dbaccess; import Java.sql.*; import Java.util.*; import Java.io.*; import Java.lang.reflect.*;
public class DBQueryBean implements Serializable { DBConnBean dbc; String sql = null; int rowcount = 0; int colcount = 0; // int limitcount = 0; Vector result = null; public String _WATCH = "";
public DBQueryBean() { dbc = new DBConnBean(); try { dbc.Connect(); } catch(Exception e) { handleException(e); } } protected void finalize() throws Throwable { super.finalize(); if (dbc != null) dbc.over(); if (result != null) result.removeAllElements(); } public String get(int row, int col) { if (result==null || row >= result.size()) return null; String r[] = (String[])result.elementAt(row); if (col >= Java.lang.reflect.Array.getLength(r)) return null; return r[col]; } public int getAffRows() { return dbc.getAffectedRows(); } public int getColumncount() { return colcount; } public String[] getRow(int row) { if (result==null || row >= result.size()) return null; return (String [])result.elementAt(row); /*String ret[] = new String[colcount]; Vector r = (Vector)result.elementAt(row); for (int i=0; i<colcount; i++) ret[i] = (String)r.elementAt(i); return ret;*/ } public int getRowcount() { return rowcount; } public void handleException(Exception e) { _WATCH = e.getMessage(); } public void init() { rowcount = 0; colcount = 0; // limitcount = 0; result = null; } public void over() throws Throwable { finalize(); } public int query(String sql) { result = new Vector(); int ret = 0; try { ResultSet rs = dbc.query(sql); if (rs == null) { ret = dbc.getAffectedRows(); } else { ResultSetMetaData rm = rs.getMetaData(); colcount = rm.getColumnCount(); while (rs.next()) { String row[] = new String[colcount]; for (int i=0; i<colcount; i++) row[i] = rs.getString(i+1); result.addElement(row); rowcount++; } rs.close(); // to release the resource. ret = result.size(); } } catch(Exception e) { handleException(e); return -1; }
return ret; } }
|