Posted on 2007-11-21 18:23
帥子 閱讀(200)
評論(0) 編輯 收藏 所屬分類:
J2EE技術專區
下面的代碼演示了一種方法用來確認已訪問調用方法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;
}
}