?? jdbc-spec.frame15.html
字號:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=gb2312">
<title></title>
</head>
<body bgcolor="#ffffff">
<table width="600">
<tr>
<td><font size="-1"><a href="jdbc-spec.frame.html">目錄</a> | <a
href="jdbc-spec.frame14.html">上一頁</a> | <a href="jdbc-spec.frame16.html">下一頁</a>
</font></td>
<td align="right"><i>JDBC<sup><font size="-2">TM</font></sup> 指南:入門</i></td>
</tr>
</table>
<hr>
<p><br>
<a name="3883"></a> </p>
<h2>附錄 A: 放棄的設計方案</h2>
<h3>A.1 使用 Holder 類型,而非 get/set 方法。</h3>
<p>在 JDBC 的初稿中,我們用“ Holder
”類型機制傳遞參數、獲取結果。這種機制是試圖在 ODBC
中模擬變量指針的用法。但當我們編寫測試示例程序時發現:該機制需要創建和捆綁
Holder 類型,而這是很煩瑣的,尤其是處理行結果時。</p>
<p><a name="4118"></a>于是我們提出了另一種設計方案,即 getXXX 和 setXXX
方法,這兩種方法在<a href="jdbc-spec.frame7.html#20240">第 7.2 節</a>和<a
href="jdbc-spec.frame7.html#4149">第 7.1 節</a>中有具體說明。在比較了各種示例程序后,我們得出的結論是:對程序員來說,getXXX/setXXX
機制使用起來更簡單些。它也使人們不用再為 JDBC API 定義成打的
Holder 類型。于是我們決定不再用 Holders 而改用 getXXX/setXXX 機制。</p>
<p><a name="4026"></a> </p>
<h4>A.1.1 用 Holder 類型傳遞參數</h4>
<p>作為 java.sql API 的一部分,我們定義了 Holder 類型集來存放 SQL
語句的參數。有了抽象基本類 Holder,也就有了特定的、不同 Java
類型且與 SQL 一起使用的子類型。例如,StringHolder
將保存字符串參數,而 ByteHolder 將保存字節參數。</p>
<p><a name="3897"></a>為使參數能傳給 SQL 語句,java.sql.Statement 類允許將
Holder 對象與某一參數關聯起來。執行語句時,將從相應的 Holder
對象讀出 IN 或 INOUT 參數值;語句結束時,OUT 或 INOUT
參數將被寫回相應的 Holder 對象。</p>
<p><a name="3898"></a>下面是 Holders 用于 IN 參數的示例: </p>
<pre><code>java.sql.Statement stmt = conn.createStatement();
</code></pre>
<pre><code>// 傳遞兩個參數,其中一個在 for 循環中每次都改變,
</code></pre>
<pre><code>// 而另一個則保持不變。
</code></pre>
<pre><code>IntHolder ih = new IntHolder();
</code></pre>
<pre><code>stmt.bindParameter(1, ih);
</code></pre>
<pre><code>StringHolder sh = new StringHolder();
</code></pre>
<pre><code>stmt.bindParameter(2, sh);
</code></pre>
<pre><code>sh.value ="Hi"
</code></pre>
<pre><code>for (int i = 0; i < 10; i++) {
</code></pre>
<pre><code> ih.value = i;
</code></pre>
<pre><code> stmt.executeUpdate("UPDATE Table2 set a = ? WHERE b = ?");
</code></pre>
<pre><code>}
</code></pre>
<p>下面是 Holder 用于 OUT 參數的示例: </p>
<pre><code>java.sql.Statement stmt = conn.createStatement();
</code></pre>
<pre><code>IntHolder ih = new IntHolder();
</code></pre>
<pre><code>stmt.bindParameter(1, ih);
</code></pre>
<pre><code>StringHolder sh = new StringHolder();
</code></pre>
<pre><code>stmt.bindParameter(2, sh);
</code></pre>
<pre><code>for (int i = 0; i < 10; i++) {
</code></pre>
<pre><code> stmt.executeUpdate("{CALL testProcedure(?, ?)}");
</code></pre>
<pre><code> byte x = ih.value;
</code></pre>
<pre><code> String s = sh.value;
</code></pre>
<pre><code>}
</code></pre>
<h4>A.1.2 <strong>用 Holder 對象獲取行結果</strong></h4>
<p>在執行語句前,應用程序員可以將 Holder
對象和某些列捆綁在一起。語句執行之后,應用程序可以用
ResultSet.next() 重復 ResultSet 以移到下一行。在應用程序移到某行時,Holder
對象將和該行的值一起 移動。這跟 ODBC 中用的 SQLBindColumn
機制相似。</p>
<p><a name="4004"></a> 下面是一個簡單示例: </p>
<pre><code>// 執行一條 SQL 語句,返回
</code></pre>
<pre><code>// 行的集合,其中第一列是 int 類型,第二列是
</code></pre>
<pre><code>// String 類型,第三列是字節數組。
</code></pre>
<pre><code>java.sql.Statement stmt = conn.createStatement();
</code></pre>
<pre><code>IntHolder ih = new IntHolder();
</code></pre>
<pre><code>stmt.bindHolder(1, ih);
</code></pre>
<pre><code>StringHolder sh = new StringHolder();
</code></pre>
<pre><code>stmt.bindHolder(2, sh);
</code></pre>
<pre><code>BytesHolder bh = new BytesHolder();
</code></pre>
<pre><code>stmt.bindHolder(3, bh);
</code></pre>
<pre><code>ResultSet r = stmt.executeQuery("SELECT a, b, c FROM Table7");
</code></pre>
<pre><code>while (r.next()) {
</code></pre>
<pre><code> // 打印輸出當前行的值。
</code></pre>
<pre><code> int i = ih.value;
</code></pre>
<pre><code> String s = sh.value;
</code></pre>
<pre><code> byte b[] = bh.value;
</code></pre>
<pre><code> System.out.println("ROW = " + i + " " + s + " " + b[0]);
</code></pre>
<pre><code>}
</code></pre>
<pre><code>
</code></pre>
<h3>A.2 候選設計:不用 fooHolder 類型,而用 foo[ ]</h3>
<strong>
<p>將來我們可能會支持列形式的捆綁,這樣就能同時讀取行塊。在使用
Holder 的同時,我們也考慮了下面一種</strong> <strong>允許以列形式進行捆綁的新設計。</strong></p>
<p><a name="3262"></a>Holder 對象能夠保存各種 Java
類型的單個實例。但單元素數組也能用作 Holder。這種方法除了一個明顯優勢之外也有些缺點。</p>
<p><a name="3264"></a>缺點之一:讀“foo f[] = new foo[1];”時感到含混。相應的
Holder 聲明“fooHolder f = new fooHolder();”卻可以對 f
是什么及為什么要分配它給出較為明確的提示。</p>
<p>缺點之二:對于每個數組類型,必須用不同的方法取代單個方法
Statement.bindColumn。這是由于所有 Holder 類型都是從 java.sql.Holder
繼承而來的,所以它們可作為參數傳給使用 java.sql.Holder
參數的通用方法(另一方面,至少避免了定義成打的 holder 類)。</p>
<p><a name="3266"></a>最后一個缺點:使用 foo[] 只能提供原始 Java
類型信息。通過定義與 SQL 一起使用的 Holder
類型集,我們卻能為諸如 CurrencyHolder 類型定義更多的域和/或語義。</p>
<p><a name="3267"></a>相應的明顯優勢是:如果我們把 foo[1]
看成是參數的容器,自然可將 foo[x]
視作一種在列形式捆綁中捆綁表中多行的途徑。這可在不修改接口的情況下即能支持列形式的捆綁。</p>
<p>如果用數組代替 Holders,那么 bindColumn
機制將使比例變換到列形式的捆綁更加易于進行。</p>
<p><a name="17410"></a> </p>
<h3>A.3 支持一次檢索多行</h3>
<p>目前我們提供的方法是在單行中檢索單列,即每次一個域。我們期望驅動程序正常情況下能預取得更大的行塊,從而減少與目標數據庫的交互量。但它也可能有助于程序員通過
JDBC API 以更大塊的方式檢索數據。</p>
<p><a name="17412"></a>Java
中最簡單的支持機制可能就是支持一些列形式的捆綁,其中程序員可以指定用作保存下面每一列的
20 個值的數組集,然后一次讀取 20 行。</p>
<p>但我們不打算在 JDBC
的第一個版本中提供這種機制。我們建議一般情況下驅動程序能預取得大小適中的行塊。</p>
<p><a name="20127"></a> </p>
<h3>A.4 ResultSet.get 方法中的列號</h3>
<p>JDBC 規范的早些版本中,各種“get”方法均不使用參數,而只按從左到右的順序返回下一列的值。我們引入
列號參數的原因就是因為對最終實例代碼的可讀性不太滿意。我們經常發現,為將它們與
SELECT 語句指定的 列匹配,需要用各種“get”調用進行計數。</p>
<p><a name="20141"></a> </p>
<h3>A.5 set 方法的方法重載</h3>
<p>在早期版本中,我們使用方法重載而不必使方法冠以各式各樣的名字(如
setByte、setBoolean 等),所有 這些方法簡稱為 setParameter,并且只通過不同的參數類型加以區別。雖然這在
Java 中是合法的,但評論 家卻說它令人費解且易于出錯,尤其是在
SQL 類型和 Java
類型之間映射不明確的情況下。經考慮后,我們同意了他們的意見。</p>
<p><a name="20152"></a> </p>
<h3>A.6 避開 registerOutParameter 方法</h3>
<p>我們討厭使用 registerOutParameter 方法。在開發 JDBC
期間,我們努力避開它,方法是讓驅動程序用數據庫元數據來確定
OUT
參數類型。但評論員的意見使我們相信,由于性能方面的原因,用
registerOutParameter 指定 OUT 參數類型會更合適。</p>
<p><a name="20172"></a> </p>
<h3>A.7 對大 OUT 參數的支持。</h3>
<p>目前我們不支持太大的 OUT 參數。如果我們要為非常大的 OUT
參數提供機制,就可能包括允許程序員注冊 java.io.OutputStreams(當語句執行時,JDBC
運行時可將 OUT 參數的數據發送到其中)。但鑒于已經有了
一種將大結果作為 ResultSet
組成部分進行處理的機制,因此比起其實際價值來說解釋可能要更難一些。</p>
<p><a name="20169"></a> </p>
<h3>A.8 支持 GetObject/getXXX</h3>
<p>由于各種 get/set 方法和通用 getObject/setObject
方法之間有重疊,因此我們考慮放棄 get/set 方法而只用
getObject/setObject。但如果程序員知道 SQL
類型,則最終的強制類型轉換和提取就顯得極其煩瑣: </p>
<p><a name="24866"></a> int i = ((Integer)r.getObject(1,
java.sql.Types.INTEGER)).intValue() </p>
<p><a name="24863"></a>于是我們決定對此作出一點讓步,即保留各種
get/set 方法作為大多數應用程序員的首選接口,但同時也增加
getObject/setObject 方法以備工具構造器和復雜應用程序使用。</p>
<p><a name="25317"></a> </p>
<h3>A.9 isNull/wasNull</h3>
<p>在決定處理 SQL NULL
的方法中,我們遇到了一些困難。不過,我們還是用 JDBC 0.50 設計了
ResultSet.isNull
方法,而且用起來也似乎頗為合意。讀列之前(或之后)都可以在列中調用
isNull 方法以檢查是否為 NULL。</p>
<pre><code>if (!ResultSet(isNull(3)) {
</code></pre>
<pre><code> count += ResultSet.getInt(3);
</code></pre>
<pre><code>}
</code></pre>
<p>遺憾的是,無情的現實否定了這種設想。事實上,不是所有的數據庫都能可靠地實現“isNull”。某些數據庫
除了讀取該列并允許一次只能讀一個給定列之外,并沒有單獨的措施來確定某一列是否為空。我們考慮的方法是:讀取列值并“記住”它以備將來之用。但在需要數據轉換時,該方法仍會出問題。</p>
<p><a name="25327"></a>在研究過多種解決方案后,我們勉強決定用 wasNull
方法代替 isNull 方法。wasNull 方法將只報告從給定的 ResultSet(或
CallableStatement)讀取的最終值是否為 SQL NULL。</p>
<p><a name="25724"></a> </p>
<h3>A.10 Java 類型名/SQL 類型名的使用。</h3>
<p>在早些版本的規范中,我們用 getXXX 和 setXXX
方法檢索結果、訪問參數,其中的 XXX 代表 SQL 類型名。在修訂版 JDBC
0.70 中,我們仍然使用 getXXX 和 setXXX 方法,但其中的 XXX 改為 Java
類型名。</p>
<p><a name="25736"></a>舉例來說,getString 已取代 getChar,而 setShort
則已取代 setSmallInt。</p>
<p>新方法的語義與它們所取代的方法的語義本質上相同。但對 Java
程序員來說,Java 類型名的使用使每種方法的含義更清晰易懂。</p>
<p><a name="20150"></a> </p>
<p><a name="20120"></a> </p>
<p><br>
</p>
<hr>
<font size="-1"><a href="jdbc-spec.frame.html">
<p>目錄</a> | <a href="jdbc-spec.frame14.html">上一頁</a> | <a
href="jdbc-spec.frame16.html">下一頁</a> </font></p>
<hr>
<address>
<a href="mailto:jdbc@wombat.eng.sun.com">jdbc@wombat.eng.sun.com</a> 或 <a
href="mailto:jdbc-odbc@wombat.eng.sun.com">jdbc-odbc@wombat.eng.sun.com</a>
</address>
<a href="../../../relnotes/SMICopyright.html"><font size="-1"><i>
<pre>版權所有© 1996 1997 Sun Microsystems, Inc. 保留所有權利。</i></font></a>
<!-- HTML generated by Suzette Pelouch on April 10, 1998 -->
</pre>
</body>
</html>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -