JDBCTM 指南:入門4 - Statement (轉)

worldblog發表於2007-12-08
JDBCTM 指南:入門4 - Statement (轉)[@more@]4 - Statement
本概述是從《JCTM Database Access from TM: A Tutorial and Annotated Reference 》這本書中摘引來的。JavaSoft 目前正在準備這本書。這是一本教程,同時也是 的重要參考手冊,它將作為 Java 系列的組成部份在 1997 年春季由 Addison-Wesley 出版公司出版。


4.1 概述
Statement 用於將 語句傳送到中。實際上有三種 Statement 物件,它們都作為在給定連線上 SQL 語句的包容器:Statement、PreparedStatement(它從 Statement 繼承而來)和 CallableStatement(它從 PreparedStatement 繼承而來)。它們都專用於傳送特定型別的 SQL 語句: Statement 物件用於執行不帶引數的簡單 SQL 語句;PreparedStatement 物件用於執行帶或不帶 IN 引數的預編譯 SQL 語句;CallableStatement 物件用於執行對資料庫已過程的。

Statement 介面提供了執行語句和獲取結果的基本方法。PreparedStatement 介面新增了處理 IN 引數的方法;而 CallableStatement 新增了處理 OUT 引數的方法。


4.1.1 建立 Statement 物件
建立了到特定資料庫的連線之後,就可用該連線傳送 SQL 語句。Statement 物件用 Connection 的方法 createStatement 建立,如下列程式碼段中所示:

Connection con = Manager.getConnection(url, "sunny", "");
Statement stmt = con.createStatement();

為了執行 Statement 物件,被髮送到資料庫的 SQL 語句將被作為引數提供給 Statement 的方法:

ResultSet rs = stmt.executeQuery(" a, b, c FROM Table2");

4.1.2 使用 Statement 物件執行語句
Statement 介面提供了三種執行 SQL 語句的方法:executeQuery、executeUpdate 和 execute。使用哪一個方法由 SQL 語句所產生的內容決定。

方法 executeQuery 用於產生單個結果集的語句,例如 SELECT 語句。

方法 executeUpdate 用於執行 INSERT、UPDATE 或 DELETE 語句以及 SQL DDL(資料定義語言)語句,例如 CREATE TABLE 和 DROP TABLE。INSERT、UPDATE 或 DELETE 語句的效果是修改表中零行或多行中的一列或多列。executeUpdate 的返回值是一個整數,指示受影響的行數(即計數)。對於 CREATE TABLE 或 DROP TABLE 等不操作行的語句,executeUpdate 的返回值總為零。

方法 execute 用於執行返回多個結果集、多個更新計數或二者組合的語句。因為多數員不會需要該高階功能,所以本概述後面將在單獨一節中對其進行介紹。

執行語句的所有方法都將關閉所呼叫的 Statement 物件的當前開啟結果集(如果存在)。這意味著在重新執行 Statement 物件之前,需要完成對當前 ResultSet 物件的處理。

應注意,繼承了 Statement 介面中所有方法的 PreparedStatement 介面都有自己的 executeQuery、executeUpdate 和 execute 方法。Statement 物件本身不包含 SQL 語句,因而必須給 Statement.execute 方法提供 SQL 語句作為引數。PreparedStatement 物件並不將 SQL 語句作為引數提供給這些方法,因為它們已經包含預編譯 SQL 語句。CallableStatement 物件繼承這些方法的 PreparedStatement 形式。對於這些方法的 PreparedStatement 或 CallableStatement 版本,使用查詢引數將丟擲 SQLException。


4.1.3 語句完成
當連線處於自動提交時,其中所執行的語句在完成時將自動提交或還原。語句在已執行且所有結果返回時,即認為已完成。對於返回一個結果集的 executeQuery 方法,在檢索完 ResultSet 物件的所有行時該語句完成。對於方法 executeUpdate,當它執行時語句即完成。但在少數呼叫方法 execute 的情況中,在檢索所有結果集或它生成的更新計數之後語句才完成。

有些 DBMS 將已儲存過程中的每條語句視為獨立的語句;而另外一些則將整個過程視為一個複合語句。在啟用自動提交時,這種差別就變得非常重要,因為它影響什麼時候呼叫 commit 方法。在前一種情況中,每條語句單獨提交;在後一種情況中,所有語句同時提交。


4.1.4 關閉 Statement 物件
Statement 物件將由 Java 垃圾收集程式自動關閉。而作為一種好的風格,應在不需要 Statement 物件時顯式地關閉它們。這將立即釋放 DBMS 資源,有助於避免潛在的問題。


4.1.5 Statement 物件中的 SQL 轉義語法
Statement 可包含使用 SQL 轉義語法的 SQL 語句。轉義語法告訴程式其中的程式碼應該以不同方式處理。驅動程式將掃描任何轉義語法,並將它轉換成特定資料庫可理解的程式碼。這使得轉義語法與 DBMS 無關,並允許程式設計師使用在沒有轉義語法時不可用的功能。

轉義子句由花括號和關鍵字界定:

{key . . . parameters . . . }

該關鍵字指示轉義子句的型別,如下所示。


escape 表示 LIKE 跳脫字元


字元“%”和“_”類似於 SQL LIKE 子句中的萬用字元(“%”匹配零個或多個字元,而“_”則匹配一個字元)。為了正確解釋它們,應在其前面加上反斜槓(“”),它是字串中的特殊跳脫字元。在查詢末尾包括如下語法即可指定用作跳脫字元的字元:

{escape 'escape-character'}


例如,下列查詢使用反斜槓字元作為跳脫字元,查詢以下劃線開頭的識別符號名:

stmt.executeQuery("SELECT name FROM ntifiers
WHERE Id LIKE `_%' {escape `'};


fn 表示標量


幾乎所有 DBMS 都具有標量值的數值、字串、時間、日期、和轉換函式。要使用這些函式,可使用如下轉義語法:關鍵字 fn 後跟所需的函式名及其引數。例如,下列程式碼呼叫函式 concat 將兩個引數連線在一起:

{fn concat("Hot", "Java")};


可用下列語法獲得當前資料庫名:

{fn user()};


標量函式可能由語法稍有不同的 DBMS 支援,而它們可能不被所有驅動程式支援。各種 DatabaseMetaData 方法將列出所支援的函式。例如,方法 getNumericFunctions 返回用逗號分隔的數值函式列表,而方法 getStringFunctions 將返回字串函式,等等。

驅動程式將轉義函式呼叫對映為相應的語法,或直接實現該函式。


d、t 和 ts 表示日期和時間文字


DBMS 用於日期、時間和時間標記文字的語法各不相同。JDBC 使用轉義子句支援這些文字的語法的 ISO 標準格式。驅動程式必須將轉義子句轉換成 DBMS 表示。

例如,可用下列語法在 JDBC SQL 語句中指定日期:

{d `yyyy-mm-dd'}


在該語法中,yyyy 為年代,mm 為月份,而 dd 則為日期。驅動程式將用等價的特定於 DBMS 的表示替換這個轉義子句。例如,如果 '28- FEB-99' 符合基本資料庫的格式,則驅動程式將用它替換 {d 1999-02-28}。

對於 TIME 和 TIMESTAMP 也有類似的轉義子句:

{t `hh:mm:ss'}
{ts `yyyy-mm-dd hh:mm:ss.f . . .'}


TIMESTAMP 中的小數點後的秒(.f . . .)部分可忽略。


call 或 ? = call 表示已儲存過程



如果資料庫支援已儲存過程,則可從 JDBC 中呼叫它們,語法為:

{call procedure_name[(?, ?, . . .)]}


或(其中過程返回結果引數):

{? = call procedure_name[(?, ?, . . .)]}


方括號指示其中的內容是可選的。它們不是語法的必要部分。

輸入引數可以為文字或引數。有關詳細資訊,參見 JDBC 指南中第 7 節,“CallableStatement”。

可透過呼叫方法 DatabaseMetaData.supportsStoredProcedures 檢查資料庫是否支援已儲存過程。



oj 表示外部連線



外部連線的語法為

{oj outer-join}


其中 outer-join 形式為

table LEFT OUTER JOIN {table / outer-join} ON search-condition


外部連線屬於高階功能。有關它們的解釋可參見 SQL 語法。JDBC 提供了三種 DatabaseMetaData 方法用於確定驅動程式支援哪些外部連線型別:supportsOuterJoins、supportullOuterJoins 和 supportsLimitedOuterJoins。


方法 Statement.setEscapeProcessing 可開啟或關閉轉義處理;預設狀態為開啟。當極為重要時,程式設計師可能想關閉它以減少處理時間。但通常它將出於開啟狀態。應注意: setEscapeProcessing 不適用於 PreparedStatement 物件,因為在呼叫該語句前它就可能已被髮送到資料庫。有關預編譯的資訊,參見 PreparedStatement。


4.1.6 使用方法 execute
execute 方法應該僅在語句能返回多個 ResultSet 物件、多個更新計數或 ResultSet 物件與更新計數的組合時使用。當執行某個已儲存過程或動態執行未知 SQL 字串(即應用程式程式設計師在編譯時未知)時,有可能出現多個結果的情況,儘管這種情況很少見。例如,使用者可能執行一個已儲存過程(使用 CallableStatement 物件 - 參見第 135 頁的 CallableStatement),並且該已儲存過程可執行更新,然後執行選擇,再進行更新,再進行選擇,等等。通常使用已儲存過程的人應知道它所返回的內容。

因為方法 execute 處理非常規情況,所以獲取其結果需要一些特殊處理並不足為怪。例如,假定已知某個過程返回兩個結果集,則在使用方法 execute 執行該過程後,必須呼叫方法 getResultSet 獲得第一個結果集,然後呼叫適當的 getXXX 方法獲取其中的值。要獲得第二個結果集,需要先呼叫 getMoreResults 方法,然後再呼叫 getResultSet 方法。如果已知某個過程返回兩個更新計數,則首先呼叫方法 getUpdateCount,然後呼叫 getMoreResults,並再次呼叫 getUpdateCount。

對於不知道返回內容,則情況更為複雜。如果結果是 ResultSet 物件,則方法 execute 返回 true;如果結果是 Java int,則返回 false。如果返回 int,則意味著結果是更新計數或執行的語句是 DDL 命令。在呼叫方法 execute 之後要做的第一件事情是呼叫 getResultSet 或 getUpdateCount。呼叫方法 getResultSet 可以獲得兩個或多個 ResultSet 物件中第一個物件;或呼叫方法 getUpdateCount 可以獲得兩個或多個更新計數中第一個更新計數的內容。

當 SQL 語句的結果不是結果集時,則方法 getResultSet 將返回 null。這可能意味著結果是一個更新計數或沒有其它結果。在這種情況下,判斷 null 真正含義的唯一方法是呼叫方法 getUpdateCount,它將返回一個整數。這個整數為呼叫語句所影響的行數;如果為 -1 則表示結果是結果集或沒有結果。如果方法 getResultSet 已返回 null(表示結果不是 ResultSet 物件),則返回值 -1 表示沒有其它結果。也就是說,當下列條件為真時表示沒有結果(或沒有其它結果):

((stmt.getResultSet() == null) && (stmt.getUpdateCount() == -1))

如果已經呼叫方法 getResultSet 並處理了它返回的 ResultSet 物件,則有必要呼叫方法 getMoreResults 以確定是否有其它結果集或更新計數。如果 getMoreResults 返回 true,則需要再次呼叫 getResultSet 來檢索下一個結果集。如上所述,如果 getResultSet 返回 null,則需要呼叫 getUpdateCount 來檢查 null 是表示結果為更新計數還是表示沒有其它結果。

當 getMoreResults 返回 false 時,它表示該 SQL 語句返回一個更新計數或沒有其它結果。因此需要呼叫方法 getUpdateCount 來檢查它是哪一種情況。在這種情況下,當下列條件為真時表示沒有其它結果:

((stmt.getMoreResults() == false) && (stmt.getUpdateCount() == -1))

下面的程式碼演示了一種方法用來確認已訪問呼叫方法 execute 所產生的全部結果集和更新計數:


stmt.execute(queryStringWithUnknownResults);
while (true) {
int rowCount = 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; // 沒有其它結果

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-989813/,如需轉載,請註明出處,否則將追究法律責任。

相關文章