乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      使用 JDBC 創(chuàng)建數(shù)據(jù)庫(kù)對(duì)象

       todaytomo 2007-03-28
      本文分析了Java DataBase Connectivity (JDBC),一個(gè)在 Java 中以面向?qū)ο蟮姆椒▉?lái)連接數(shù)據(jù)庫(kù)的技術(shù)。它是對(duì) ODBC API 進(jìn)行的一種面向?qū)ο蟮姆庋b和重新設(shè)計(jì),它易于學(xué)習(xí)和使用,并且它能夠使您編寫(xiě)不依賴供應(yīng)商的代碼,用以查詢和操縱數(shù)據(jù)庫(kù)。JDBC 提供了一些相當(dāng)?shù)蛯拥姆椒▉?lái)存取數(shù)據(jù)庫(kù),同時(shí)也在相當(dāng)高層提供了功能強(qiáng)大的對(duì)象來(lái)處理數(shù)據(jù)庫(kù)。

      什么是數(shù)據(jù)庫(kù)?

      數(shù)據(jù)庫(kù)是以某種文件結(jié)構(gòu)存儲(chǔ)的一系列信息表,這種文件結(jié)構(gòu)使您能夠訪問(wèn)這些表、選擇表中的列、對(duì)表進(jìn)行排序以及根據(jù)各種標(biāo)準(zhǔn)選擇行。數(shù)據(jù)庫(kù)通常有多個(gè) 索引與這些表中的許多列相關(guān)聯(lián),所以我們能盡可能快地訪問(wèn)這些表。

      在進(jìn)行計(jì)算時(shí),數(shù)據(jù)庫(kù)比其它類型的結(jié)構(gòu)更常用。您會(huì)發(fā)現(xiàn)在員工記錄和薪資系統(tǒng)中數(shù)據(jù)庫(kù)處于核心地位,在旅行計(jì)劃系統(tǒng)中以及在產(chǎn)品生產(chǎn)和銷(xiāo)售的整個(gè)過(guò)程中都可以發(fā)現(xiàn)數(shù)據(jù)庫(kù)。

      以員工記錄為例,您可以設(shè)想一個(gè)含有員工姓名、地址、工資、扣稅以及津貼等內(nèi)容的表。讓我們考慮一下這些內(nèi)容可能如何組織在一起。您可以設(shè)想一個(gè)表包含員工姓名、地址和電話號(hào)碼。您希望保存的其它信息可能包括工資、工資范圍、上次加薪時(shí)間、下次加薪時(shí)間、員工業(yè)績(jī)?cè)u(píng)定等內(nèi)容。

      這些內(nèi)容是否應(yīng)保存在一個(gè)表格中?幾乎可以肯定不應(yīng)該如此。不同類別的員工的工資范圍可能沒(méi)有區(qū)別;這樣,您可以僅將員工類型儲(chǔ)存在員工記錄表中,而將工資范圍儲(chǔ)存在另一個(gè)表中,通過(guò)類型編號(hào)與這個(gè)表關(guān)聯(lián)??紤]以下情況:

      Key Lastname SalaryType SalaryType Min Max
      1 Adams 2 1 30000 45000
      2 Johnson 1 2 45000 60000
      3 Smyth 3 3 60000 75000
      4 Tully 1
      5 Wolff 2

      SalaryType 列中的數(shù)據(jù)引用第二個(gè)表。我們可以想象出許多種這樣的表,如用于存儲(chǔ)居住城市和每個(gè)城市的稅值、健康計(jì)劃扣除金額等的表。每個(gè)表都有一個(gè)主鍵列(如上面兩個(gè)表中最左邊的列)和若干數(shù)據(jù)列。在數(shù)據(jù)庫(kù)中建立表格既是一門(mén)藝術(shù),也是一門(mén)科學(xué)。這些表的結(jié)構(gòu)由它們的 范式指出。我們通常說(shuō)表屬于第一、第二或第三范式,簡(jiǎn)稱為1NF、2NF或3NF。

      第一范式:表中的每個(gè)表元應(yīng)該只有一個(gè)值(永遠(yuǎn)不可能是一個(gè)數(shù)組)。(1NF)

      第二范式:滿足1NF,并且每一個(gè)副鍵列完全依賴于主鍵列。這表示主鍵和該行中的剩余表元之間是1對(duì)1的關(guān)系。(2NF)

      第三范式:滿足2NF,并且所有副鍵列是互相獨(dú)立的。任何一個(gè)數(shù)據(jù)列中包含的值都不能從其他列的數(shù)據(jù)計(jì)算得到。(3NF)

      現(xiàn)在,幾乎所有的數(shù)據(jù)庫(kù)都是基于“第三范式(3NF)”創(chuàng)建的。這意味著通常都有相當(dāng)多的表,每個(gè)表中的信息列都相對(duì)較少。

      從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)

      假設(shè)我們希望生成一個(gè)包含員工及其工資范圍的表,在我們?cè)O(shè)計(jì)的一個(gè)練習(xí)中將使用這個(gè)表。這個(gè)表格不是直接存在在數(shù)據(jù)庫(kù)中,但可以通過(guò)向數(shù)據(jù)庫(kù)發(fā)出一個(gè)查詢來(lái)構(gòu)建它。我們希望得到如下所示的一個(gè)表:

      Name Min Max
      Adams $45,000.00 $60,000.00
      Johnson $30,000.00 $45,000.00
      Smyth $60,000.00 $75,000.00
      Tully $30,000.00 $45,000.00
      Wolff $45,000.00 $60,000.00

      或者,按照工資遞增的順序排序

      Name Min Max
      Tully $30,000.00 $45,000.00
      Johnson $30,000.00 $45,000.00
      Wolff $45,000.00 $60,000.00
      Adams $45,000.00 $60,000.00
      Smyth $60,000.00 $75,000.00

      我們發(fā)現(xiàn),獲得這些表的查詢形式如下所示

              SELECT DISTINCTROW Employees.Name, SalaryRanges.Min,
                                  SalaryRanges.Max FROM Employees INNER JOIN SalaryRanges ON Employees.SalaryKey = SalaryRanges.SalaryKey
                                  ORDER BY SalaryRanges.Min;
                                  

      這種語(yǔ)言稱為結(jié)構(gòu)化查詢語(yǔ)言,即 SQL (一般讀作 "sequel" ),而且它是幾乎目前所有數(shù)據(jù)庫(kù)都可以使用的一種語(yǔ)言。這幾年已頒布了若于 SQL 標(biāo)準(zhǔn),而且大多數(shù) PC 數(shù)據(jù)庫(kù)支持大部分 ANSI 標(biāo)準(zhǔn)。 SQL-92 標(biāo)準(zhǔn)被認(rèn)為是一種基礎(chǔ)標(biāo)準(zhǔn),而且已更新多次。然而,沒(méi)有一種數(shù)據(jù)庫(kù)可以完美地支持后來(lái)的 SQL 版本,而且大多數(shù)數(shù)據(jù)庫(kù)都提供了多種 SQL 擴(kuò)展,以支持他們數(shù)據(jù)庫(kù)獨(dú)有的性能。

      數(shù)據(jù)庫(kù)的種類

      由于 PC 已成為主要的辦公工具,因此,已開(kāi)發(fā)出在 PC 上的大量流行的數(shù)據(jù)庫(kù),這些數(shù)據(jù)庫(kù)都是可以自管理的。它們包括初級(jí)數(shù)據(jù)庫(kù),如 MicrosoftWorks ,還包括更為復(fù)雜的數(shù)據(jù)庫(kù),如 Approach 、 dBase 、 Borland Paradox 、 Microsoft Access 和 FoxBase 。

      另一類PC數(shù)據(jù)庫(kù)包括那些可由許多PC客戶機(jī)通過(guò)服務(wù)器訪問(wèn)的數(shù)據(jù)庫(kù)。其中包括IBM DB/2、Microsoft SQL Server、Oracle、Sybase、SQLBase和XDB。所有這些數(shù)據(jù)庫(kù)產(chǎn)品都支持多種相對(duì)類似的SQL方言,因此,所有數(shù)據(jù)庫(kù)最初看起來(lái)好象可以互換。當(dāng)然,它們 不能互換的原因是每種數(shù)據(jù)庫(kù)都有不同的性能特征,而且每一種都有不同的用戶界面和編程接口。您可能會(huì)想,既然它們都支持SQL,對(duì)它們進(jìn)行的編程也應(yīng)該相似,但這是絕對(duì)錯(cuò)誤的,因?yàn)槊糠N數(shù)據(jù)庫(kù)都使用其自己方式接收SQL查詢,并使用其自己的方式返回結(jié)果。這就自然引出了一種新一代的標(biāo)準(zhǔn):ODBC

      ODBC

      如果我們能夠以某種方式編寫(xiě)不依賴于特定廠商的數(shù)據(jù)庫(kù)的代碼,并且能夠不改變自己的調(diào)用程序即可從這些數(shù)據(jù)庫(kù)中得到相同的結(jié)果,那將是一件很好的事。如果我們可以僅為所有這些數(shù)據(jù)庫(kù)編寫(xiě)一些封裝,使它們具有相似的編程接口,這種對(duì)數(shù)據(jù)庫(kù)編程獨(dú)立于供應(yīng)商的特性將很容易實(shí)現(xiàn)。

      Microsoft于1992年首先嘗試了這一技巧,該公司發(fā)布了一個(gè)規(guī)范,稱為對(duì)象數(shù)據(jù)庫(kù)連接性。這被認(rèn)為是在Windows環(huán)境下連接所有數(shù)據(jù)庫(kù)的答案。與所有軟件的第一個(gè)版本相同,它也經(jīng)歷了一些發(fā)展的困擾,在1994年推出了另一個(gè)版本,該版本運(yùn)行速度更快,而且更為穩(wěn)定。它也是第一個(gè)32位的版本。另外,ODBC開(kāi)始向Windows之外的其它平臺(tái)發(fā)展,到目前為止,它在PC和工作站領(lǐng)域已十分普遍。幾乎每個(gè)主要的數(shù)據(jù)庫(kù)廠商都提供ODBC驅(qū)動(dòng)程序。

      然而,ODBC并不是我們最初想象的靈丹妙藥。許多數(shù)據(jù)庫(kù)廠商都將ODBC作為其標(biāo)準(zhǔn)接口之外的“備選接口”,而且對(duì)ODBC的編程微不足道。與其它Windows編程一樣,它包括句柄、指針和選項(xiàng),使其難以掌握。最后一點(diǎn),ODBC不是中立的標(biāo)準(zhǔn)。它由Microsoft公司開(kāi)發(fā),并由該公司不斷改進(jìn),而微軟同時(shí)也推出了我們所有人所使用的極具競(jìng)爭(zhēng)性的軟件平臺(tái),這使得ODBC的未來(lái)難以預(yù)測(cè)。

      什么是JDBC?

      JDBC 是一組首字母縮寫(xiě),曾經(jīng)代表 “Java DataBaseConnectivity” ,但現(xiàn)在它本身已成為一個(gè)商標(biāo)符號(hào)。它是對(duì) ODBC API 進(jìn)行的一種面向?qū)ο蟮姆庋b和重新設(shè)計(jì),它易于學(xué)習(xí)和使用,并且它真正能夠使您編寫(xiě)不依賴廠商的代碼,用以查詢和操縱數(shù)據(jù)庫(kù)。盡管它與所有 Java API 一樣,都是面向?qū)ο蟮?,但它并不是很高?jí)別的對(duì)象集,在本章的剩余部分,我們將提出更高級(jí)別的方法。

      除Microsoft之外,多數(shù)廠商都采用了JDBC,并為其數(shù)據(jù)庫(kù)提供了JDBC驅(qū)動(dòng)程序;這使您可輕松地真正編寫(xiě)幾乎完全不依賴數(shù)據(jù)庫(kù)的代碼。另外,JavaSoft和Intersolv已開(kāi)發(fā)了一種稱為JDBC-ODBCBridge的產(chǎn)品,可使您連接還沒(méi)有直接的JDBC驅(qū)動(dòng)程序的數(shù)據(jù)庫(kù)。支持JDBC的所有數(shù)據(jù)庫(kù)必須至少可以支持SQL-92標(biāo)準(zhǔn)。這在很大程度上實(shí)現(xiàn)了跨數(shù)據(jù)庫(kù)和平臺(tái)的可移植性。

      安裝和使用JDBC

      JDBC 的類都被歸到 java.sql

      包中,在安裝 Java JDK 1.1 或更高版本時(shí)會(huì)自動(dòng)安裝。然而,如果您想使用 JDBC-ODBC 橋,還必須安裝兩個(gè)另外的程序包。首先,如果您使用 Windows95 ,則必須將您的 ODBC 驅(qū)動(dòng)程序升級(jí)為 32 位驅(qū)動(dòng)程序,您可從 Microsoft 的網(wǎng)站下載。這個(gè)驅(qū)動(dòng)程序在 Microsoft 的網(wǎng)站上很難找到;請(qǐng)搜索 DataAcc.exe 并進(jìn)行下載和安裝。

      JDBC-ODBC驅(qū)動(dòng)程序可從Sun的Java網(wǎng)站( http://java.)輕松地找到并下載。在您擴(kuò)充并安裝了這個(gè)驅(qū)動(dòng)程序后,必須執(zhí)行下列步驟:

      1. \jdbc-odbc\classes; 路徑添加到您的PATH環(huán)境變量中。
      2. \jdbc-odbc\classes; 路徑添加到您的CLASSPATH環(huán)境變量中。
      3. 在Windows 95環(huán)境下,將它們放入autoexec.bat文件中,重新引導(dǎo),以使所有設(shè)置生效。
      4. 在Windows NT環(huán)境下,將它們添加到“控制面板”中“系統(tǒng)”對(duì)象的“環(huán)境”選項(xiàng)卡中,退出并重新登錄,以使其生效。

      JDBC驅(qū)動(dòng)程序的類型

      Java 程序連接數(shù)據(jù)庫(kù)的方法實(shí)際上有四種:
      1. JDBC-ODBC橋和ODBC驅(qū)動(dòng)程序--在這種方式下,這是一個(gè)本地解決方案,因?yàn)镺DBC驅(qū)動(dòng)程序和橋代碼必須出現(xiàn)在用戶的每臺(tái)機(jī)器中。從根本上說(shuō)這是一個(gè)臨時(shí)解決方案。
      2.  

      3. 本機(jī)代碼和Java驅(qū)動(dòng)程序--它用另一個(gè)本地解決方案(該平臺(tái)上的Java可調(diào)用的本機(jī)代碼)取代 ODBC 和 JDBC-ODBC 橋。
      4.  

      5. JDBC網(wǎng)絡(luò)的純Java驅(qū)動(dòng)程序--由Java驅(qū)動(dòng)程序翻譯的JDBC形成傳送給服務(wù)器的獨(dú)立協(xié)議。然后,服務(wù)器可連接任何數(shù)量的數(shù)據(jù)庫(kù)。這種方法使您可能從客戶機(jī)Applet中調(diào)用服務(wù)器,并將結(jié)果返回到您的Applet。在這種情況下,中間件軟件提供商可提供服務(wù)器。
      6.  

      7. 本機(jī)協(xié)議Java驅(qū)動(dòng)程序-- Java驅(qū)動(dòng)程序直接轉(zhuǎn)換為該數(shù)據(jù)庫(kù)的協(xié)議并進(jìn)行調(diào)用。這種方法也可以通過(guò)網(wǎng)絡(luò)使用,而且可以在Web瀏覽器的Applet中顯示結(jié)果。在這種情況下,每個(gè)數(shù)據(jù)庫(kù)廠商將提供驅(qū)動(dòng)程序。

      如果您希望編寫(xiě)代碼來(lái)處理 PC 客戶機(jī)數(shù)據(jù)庫(kù),如 dBase 、 Foxbase 或 Access ,則您可能會(huì)使用第一種方法,并且擁有用戶機(jī)器上的所有代碼。更大的客戶機(jī) - 服務(wù)器數(shù)據(jù)庫(kù)產(chǎn)品(如 IBM 的 DB2 )已提供了第 3 級(jí)別的驅(qū)動(dòng)程序。

      兩層模型和三層模型

      當(dāng)數(shù)據(jù)庫(kù)和查詢它的應(yīng)用程序在同一臺(tái)機(jī)器上,而且沒(méi)有服務(wù)器代碼的干預(yù)時(shí),我們將生成的程序稱為 兩層模型。一層是應(yīng)用程序,而另一層是數(shù)據(jù)庫(kù)。在 JDBC-ODBC 橋系統(tǒng)中通常是這種情況。

      當(dāng)一個(gè)應(yīng)用程序或applet調(diào)用服務(wù)器,服務(wù)器再去調(diào)用數(shù)據(jù)庫(kù)時(shí),我們稱其為 三層模型。當(dāng)您調(diào)用稱為“服務(wù)器”的程序時(shí)通常是這種情況。

      編寫(xiě)JDBC代碼訪問(wèn)數(shù)據(jù)庫(kù)

      現(xiàn)在,我們將開(kāi)始看一下如何編寫(xiě) Java 程序來(lái)訪問(wèn)數(shù)據(jù)庫(kù)。我們要使用的數(shù)據(jù)庫(kù)是一個(gè)稱為 groceries.mdb 的 Microsoft Access 數(shù)據(jù)庫(kù)。此數(shù)據(jù)庫(kù)中的數(shù)據(jù)由三個(gè)本地雜貨店中一些常見(jiàn)商品的價(jià)格組成。食品表如下所示:

      FoodKey FoodName
      1 Apples
      2 Oranges
      3 Hamburger
      4 Butter
      5 Milk
      6 Cola
      7 Greenbeans

      雜貨店表如下所示:

      StoreKey StoreName
      1 Stop andShop
      2 VillageMarket
      3 Waldbaum‘s

      雜貨店定價(jià)表僅由這三個(gè)表格中的鍵值和價(jià)格組成:

      FSKey StoreKey FoodKey Price
      1 1 1 $0.27
      2 2 1 $0.29
      3 3 1 $0.33
      4 1 2 $0.36
      5 2 2 $0.29
      6 3 2 $0.47
      7 1 3 $1.98
      8 2 3 $2.45
      9 3 3 $2.29
      10 1 4 $2.39
      11 2 4 $2.99
      12 3 4 $3.29
      13 1 5 $1.98
      14 2 5 $1.79
      15 3 5 $1.89
      16 1 6 $2.65
      17 2 6 $3.79
      18 3 6 $2.99
      19 1 7 $2.29
      20 2 7 $2.19
      21 3 7 $1.99

      用ODBC注冊(cè)您的數(shù)據(jù)庫(kù)

      在 Windows 95 或 NT 環(huán)境下訪問(wèn) ODBC 數(shù)據(jù)庫(kù)之前,必須使用控制面板中的 ODBC 驅(qū)動(dòng)程序?qū)λM(jìn)行注冊(cè)。在 Windows 95 環(huán)境下,就是 “ 控制面板 ” 程序中的 ODBC 圖標(biāo)。在 Windows NT 環(huán)境下,您會(huì)在 “ 開(kāi)始 ” 菜單中找到此程序。(如果找不到,您需要安裝上述的 ODBC 驅(qū)動(dòng)程序,即 WX1350.exe )。

      雙擊ODBC圖標(biāo),然后單擊“添加”,如圖1所示。然后選擇數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序(此處使用MicrosoftAccess),然后單擊“確定”。在“數(shù)據(jù)源名”和“描述”中分別鍵入數(shù)據(jù)源名稱(Groceries)和數(shù)據(jù)庫(kù)說(shuō)明(Groceryprices)(這兩項(xiàng)都不需要和文件名相關(guān)),然后單擊“選取”,找到數(shù)據(jù)庫(kù),并選擇該數(shù)據(jù)庫(kù)。找到該數(shù)據(jù)庫(kù)后,屏幕將如圖2所示。單擊“確定”,然后單擊“關(guān)閉”來(lái)關(guān)閉面板。


      ODBC Data Source Administrator
      圖1:ODBC控制面板設(shè)置屏幕。


      ODBC Microsoft Access 97 安裝
      圖2:在ODBC控制面板中選擇數(shù)據(jù)庫(kù)和說(shuō)明。


      連接數(shù)據(jù)庫(kù)

      所有與數(shù)據(jù)庫(kù)有關(guān)的對(duì)象和方法都在 java.sql 包中,因此在使用 JDBC 的程序中必須加入 "import java.sql.* " 。 JDBC 要連接 ODBC 數(shù)據(jù)庫(kù),您必須首先加載 JDBC-ODBC 橋驅(qū)動(dòng)程序

                Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                                  

      該語(yǔ)句加載驅(qū)動(dòng)程序,并創(chuàng)建該類的一個(gè)實(shí)例。然后,要連接一個(gè)特定的數(shù)據(jù)庫(kù),您必須創(chuàng)建 Connect 類的一個(gè)實(shí)例,并使用 URL 語(yǔ)法連接數(shù)據(jù)庫(kù)。

              String url = "jdbc:odbc:Grocery prices";
                                  Connection con = DriverManager.getConnection(url);
                                  

      請(qǐng)注意,您使用的數(shù)據(jù)庫(kù)名是您在 ODBC 設(shè)置面板中輸入的 “ 數(shù)據(jù)源 ” 名稱。

      URL語(yǔ)法可能因數(shù)據(jù)庫(kù)類型的不同而變化極大。

              jdbc:
                                  subprotocol:
                                  subname
                                  

      第一組字符代表連接 協(xié)議,并且始終是 jdbc 。還可能有一個(gè) 子協(xié)議,在此處,子協(xié)議被指定為 odbc 。它規(guī)定了一類數(shù)據(jù)庫(kù)的連通性機(jī)制。如果您要連接其它機(jī)器上的數(shù)據(jù)庫(kù)服務(wù)器,可能也要指定該機(jī)器和一個(gè)子目錄:
              jdbc:bark//doggie/elliott
                                  

      最后,您可能要指定用戶名和口令,作為連接字符串的一部分:
              jdbc:bark//doggie/elliot;UID=GoodDog;PWD=woof
                                  

      訪問(wèn)數(shù)據(jù)庫(kù)

      一旦連接到數(shù)據(jù)庫(kù),就可以請(qǐng)求表名以及表列的名稱和內(nèi)容等信息,而且您可以運(yùn)行 SQL 語(yǔ)句來(lái)查詢數(shù)據(jù)庫(kù)或者添加或修改其內(nèi)容。可用來(lái)從數(shù)據(jù)庫(kù)中獲取信息的對(duì)象有:

      DatabaseMetaData 有關(guān)整個(gè)數(shù)據(jù)庫(kù)的信息:表名、表的索引、數(shù)據(jù)庫(kù)產(chǎn)品的名稱和版本、數(shù)據(jù)庫(kù)支持的操作。
      ResultSet 關(guān)于某個(gè)表的信息或一個(gè)查詢的結(jié)果。您必須逐行訪問(wèn)數(shù)據(jù)行,但是您可以任何順序訪問(wèn)列。
      ResultSetMetaData 有關(guān)ResultSet中列的名稱和類型的信息。

      盡管每個(gè)對(duì)象都有大量的方法讓您獲得數(shù)據(jù)庫(kù)元素的極為詳細(xì)的信息,但在每個(gè)對(duì)象中都有幾種主要的方法使您可獲得數(shù)據(jù)的最重要信息。然而,如果您希望看到比此處更多的信息,建議您學(xué)習(xí)文檔以獲得其余方法的說(shuō)明。

      ResultSet

      ResultSet 對(duì)象是 JDBC 中最重要的單個(gè)對(duì)象。從本質(zhì)上講,它是對(duì)一個(gè)一般寬度和未知長(zhǎng)度的表的一種抽象。幾乎所有的方法和查詢都將數(shù)據(jù)作為 ResultSet 返回。 ResultSet 包含任意數(shù)量的命名列,您可以按名稱訪問(wèn)這些列。它還包含一個(gè)或多個(gè)行,您可以按順序自上而下逐一訪問(wèn)。在您使用 ResultSet 之前,必須查詢它包含多少個(gè)列。此信息存儲(chǔ)在 ResultSetMetaData 對(duì)象中。

              //
                                  從元數(shù)據(jù)中獲得列數(shù)
                                  ResultSetMetaData rsmd;
                                  rsmd = results.getMetaData();
                                  numCols = rsmd.getColumnCount();
                                  

      當(dāng)您獲得一個(gè)ResultSet時(shí),它正好指向第一行之前的位置。您可以使用 next() 方法得到其他每一行,當(dāng)沒(méi)有更多行時(shí),該方法會(huì)返回 false 。由于從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)可能會(huì)導(dǎo)致錯(cuò)誤,您必須始終將結(jié)果集處理語(yǔ)句包括在一個(gè) try 塊中。

              try
                                  {
                                  rsmd = results.getMetaData();
                                  numCols = rsmd.getColumnCount();
                                  boolean more = results.next();
                                  while (more)
                                  {
                                  for (i = 1; i <= numCols; i++)
                                  System.out.print(results.getString(i)+" ");
                                  System.out.println();
                                  more = results.next();
                                  }
                                  results.close();
                                  }
                                  catch(Exception e)
                                  {System.out.println(e.getMessage());}
                                  

      您可以多種形式獲取 ResultSet 中的數(shù)據(jù),這取決于每個(gè)列中存儲(chǔ)的數(shù)據(jù)類型。另外,您可以按列序號(hào)或列名獲取列的內(nèi)容。請(qǐng)注意,列序號(hào)從 1 開(kāi)始,而不是從 0 開(kāi)始。 ResultSet 對(duì)象的一些最常用方法如下所示。

      getInt(int); 將序號(hào)為 int 的列的內(nèi)容作為整數(shù)返回。
      getInt(String); 將名稱為 String 的列的內(nèi)容作為整數(shù)返回。
      getFloat(int); 將序號(hào)為 int 的列的內(nèi)容作為一個(gè) float 型數(shù)返回。
      g<tt>etFloat(String);</tt> 將名稱為 String 的列的內(nèi)容作為 float 型數(shù)返回。
      getDate(int); 將序號(hào)為 int 的列的內(nèi)容作為日期返回。
      getDate(String); 將名稱為 String 的列的內(nèi)容作為日期返回。
      next(); 將行指針移到下一行。如果沒(méi)有剩余行,則返回 false 。
      close(); 關(guān)閉結(jié)果集。
      getMetaData(); 返回 ResultSetMetaData 對(duì)象。

      ResultSetMetaData

      您使用 getMetaData() 方法從 ResultSet 中獲取 ResultSetMetaData 對(duì)象。您可以使用此對(duì)象獲得列的數(shù)目和類型以及每一列的名稱。

                    getColumnCount();
                                              

      返回 ResultSet 中的列數(shù)。
      getColumnName(int); 返回列序號(hào)為 int 的列名。
      getColumnLabel(int); 返回此列暗含的標(biāo)簽。
      isCurrency(int); 如果此列包含帶有貨幣單位的一個(gè)數(shù)字,則返回 true 。
      isReadOnly(int); 如果此列為只讀,則返回 true 。
      isAutoIncrement(int); 如果此列自動(dòng)遞增,則返回 true 。這類列通常為鍵,而且始終是只讀的。
      getColumnType(int); 返回此列的SQL數(shù)據(jù)類型。這些數(shù)據(jù)類型包括

      BIGINT
      BINARY
      BIT
      CHAR
      DATE
      DECIMAL
      DOUBLE
      FLOAT
      INTEGER
      LONGVARBINARY
      LONGVARCHAR

      NULL
      NUMERIC
      OTHER
      REAL
      SMALLINT
      TIME
      TIMESTAMP
      TINYINT
      VARBINARY
      VARCHAR

      DatabaseMetaData

      DatabaseMetaData

      對(duì)象可為您提供整個(gè)數(shù)據(jù)庫(kù)的信息。您主要用它獲取數(shù)據(jù)庫(kù)中表的名稱,以及表中列的名稱。由于不同的數(shù)據(jù)庫(kù)支持不同的 SQL 變體,因此,也有多種方法查詢數(shù)據(jù)庫(kù)支持哪些 SQL 方法。

      getCatalogs() 返回該數(shù)據(jù)庫(kù)中的信息目錄列表。使用 JDBC-ODBC Bridge 驅(qū)動(dòng)程序,您可以獲得用 ODBC 注冊(cè)的數(shù)據(jù)庫(kù)列表。這很少用于 JDBC-ODBC 數(shù)據(jù)庫(kù)。
      getTables(catalog, schema, tableNames, columnNames) 返回表名與 tableNames 相符而且列名與 columnNames 相符的所有表的說(shuō)明。
      getColumns(catalog, schema, tableNames,columnNames) 返回表名與 tableNames 相符而且列名與 columnNames 相符的所有表列說(shuō)明。
      getURL(); 獲得您所連接的URL名稱。
      getDriverName(); 獲得您所連接的數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序的名稱。

      獲取有關(guān)表的信息

      您可以使用 DataBaseMetaData 的 getTables() 方法來(lái)獲取數(shù)據(jù)庫(kù)中表的信息。這個(gè)方法有如下 4 個(gè) String 參數(shù):

              results =
                                  dma.getTables(catalog, schema, tablemask, types[]);
                                  

      其中參數(shù)的意義是:

      catalog 要在其中查找表名的目錄名。對(duì)于 JDBC-ODBC 數(shù)據(jù)庫(kù)以及許多其他數(shù)據(jù)庫(kù)而言,可將其設(shè)置為 null。這些數(shù)據(jù)庫(kù)的目錄項(xiàng)實(shí)際上是它在文件系統(tǒng)中的絕對(duì)路徑名稱。
      schema 要包括的數(shù)據(jù)庫(kù)“方案”。許多數(shù)據(jù)庫(kù)不支持方案,而對(duì)另一些數(shù)據(jù)庫(kù)而言,它代表數(shù)據(jù)庫(kù)所有者的用戶名。一般將它設(shè)置為 null 。
      tablemask 一個(gè)掩碼,用來(lái)描述您要檢索的表的名稱。如果您希望檢索所有表名,則將其設(shè)為通配符 % 。 請(qǐng)注意, SQL 中的通配符是 %符號(hào),而不是一般PC用戶的*符號(hào)。
      types[] 這是描述您要檢索的表的類型的String數(shù)組。數(shù)據(jù)庫(kù)中通常包括許多用于內(nèi)部處理的表,而對(duì)作為用戶的您沒(méi)什么價(jià)值。如果它是空值,則您會(huì)得到所有這些表。如果您將其設(shè)為包含字符串“ TABLES ”的單元素?cái)?shù)組,您將僅獲得對(duì)用戶有用的表格。

      用于從數(shù)據(jù)庫(kù)中獲取表名的簡(jiǎn)單代碼相當(dāng)于獲取 DatabaseMetaData 對(duì)象,并從其中檢索表名:

              con = DriverManager.getConnection(url);
                                  //獲取數(shù)據(jù)庫(kù)的元數(shù)據(jù)
                                  dma =con.getMetaData();
                                  //將數(shù)據(jù)庫(kù)中的表的名稱轉(zhuǎn)儲(chǔ)出來(lái)
                                  String[] types = new String[1];
                                  types[0] = "TABLES"; //設(shè)置查詢類型
                                  //請(qǐng)注意通配符是
                                  % 符號(hào)(而不是
                                  “*”)
                                  results = dma.getTables(null, null, "%", types);
                                  

      然后,我們可以打印出表名,正如我們上面所做的那樣:

              boolean more = results.next();
                                  while (more)
                                  {
                                  for (i = 1; i <= numCols; i++)
                                  System.out.print(results.getString(i)+" ");
                                  System.out.println();
                                  more = results.next();
                                  }
                                  

      如前文所述,將所有代碼包括在 try 塊中。

      執(zhí)行SQL查詢

      我們已經(jīng)理解了 JDBC 的基本對(duì)象,現(xiàn)在就可以執(zhí)行 SQL 查詢了。查詢是作為 Statement 對(duì)象的方法執(zhí)行的,您很容易從 Connection 對(duì)象獲得 Statement 對(duì)象:

              String query = "SELECT FoodName FROM Food;";
                                  ResultSet results;
                                  try
                                  {
                                  Statement stmt = con.createStatement();
                                  results = stmt.executeQuery(query);
                                  }
                                  catch (Exception e)
                                  {System.out.println("query exception");}
                                  

      請(qǐng)注意,這個(gè)簡(jiǎn)單的查詢返回 Food 表中的整個(gè) FoodName 列。您使用像這樣的簡(jiǎn)單查詢獲取整個(gè)列的內(nèi)容。請(qǐng)注意,查詢的查詢本身是一個(gè) ResultSet ,您可以用我們上面剛討論過(guò)的方法對(duì)它進(jìn)行處理。

      打印ResultSet

      因?yàn)槲覀兛偸且獜?ResultSets 中打印數(shù)據(jù),我們可以設(shè)計(jì)一種簡(jiǎn)單的方法,將整個(gè) ResultSet 轉(zhuǎn)儲(chǔ)出來(lái),包括表名稱元數(shù)據(jù)。該子程序如下所示:

              private void dumpResults(String head)
                                  {
                                  //
                                  這是打印列標(biāo)頭和每列的內(nèi)容的
                                  //
                                  通用方法
                                  System.out.println(head);
                                  try
                                  {
                                  //
                                  從元數(shù)據(jù)中獲取列數(shù)
                                  rsmd = results.getMetaData();
                                  numCols = rsmd.getColumnCount();
                                  //
                                  打印列名
                                  for (i = 1; i<= numCols; i++)
                                  System.out.print(rsmd.getColumnName(i)+" ");
                                  System.out.println();
                                  //
                                  打印列內(nèi)容
                                  boolean more = results.next();
                                  while (more)
                                  {
                                  for (i = 1; i <= numCols; i++)
                                  System.out.print(results.getString(i)+" ";
                                  System.out.println();
                                  more = results.next();
                                  }
                                  }
                                  catch(Exception e)
                                  {System.out.println(e.getMessage());}
                                  }
                                  

      一個(gè)簡(jiǎn)單的JDBC程序

      我們已經(jīng)學(xué)習(xí)了 JDBC 的所有基本功能,現(xiàn)在我們可以編寫(xiě)一個(gè)簡(jiǎn)單的程序,該程序打開(kāi)數(shù)據(jù)庫(kù),打印它的表名以及某一表列的內(nèi)容,然后對(duì)該數(shù)據(jù)庫(kù)執(zhí)行查詢。此程序如下所示:

              import java.net.URL;
                                  import java.sql.*;
                                  import java.util.*;
                                  class JdbcOdbc_test
                                  {
                                  ResultSet results;
                                  ResultSetMetaData rsmd;
                                  DatabaseMetaData dma;
                                  Connection con;
                                  int numCols, i;
                                  //--
                                  public JdbcOdbc_test()
                                  {
                                  String url = "jdbc:odbc:Grocery prices";
                                  String query = "SELECT DISTINCTROW FoodName FROM Food " + "WHERE (FoodName like ‘C%‘);";
                                  try
                                  {
                                  //
                                  加載 JDBC-ODBC 橋驅(qū)動(dòng)程序
                                  Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
                                  //連接數(shù)據(jù)庫(kù)
                                  con = DriverManager.getConnection(url);
                                  //獲取數(shù)據(jù)庫(kù)的元數(shù)據(jù)
                                  dma =con.getMetaData();
                                  System.out.println("Connected to:"+dma.getURL());
                                  System.out.println("Driver "+dma.getDriverName());
                                  //將數(shù)據(jù)庫(kù)中的表的名稱轉(zhuǎn)儲(chǔ)出來(lái)
                                  String[] types = new String[1];
                                  types[0] = "TABLES";
                                  //請(qǐng)注意通配符是 % 符號(hào)(而不是“*”)
                                  results = dma.getTables(null, null, "%", types);
                                  dumpResults("--Tables--");
                                  results.close();
                                  }
                                  catch (Exception e)
                                  {System.out.println(e);}
                                  //獲取表列的名稱
                                  System.out.println("--Column Names--");
                                  try {
                                  results =
                                  dma.getColumns(null, null, "FoodPrice", null);
                                  ResultSetMetaData rsmd = results.getMetaData();
                                  int numCols = rsmd.getColumnCount();
                                  while (results.next() )
                                  String cname = results.getString("COLUMN_NAME");
                                  System.out.print(cname + " ");
                                  System.out.println();
                                  results.close();
                                  }
                                  catch (Exception e)
                                  {System.out.println(e);}
                                  //列出一個(gè)列的內(nèi)容 -- 這是一個(gè)查詢
                                  try {
                                  Statement stmt = con.createStatement();
                                  results =
                                  stmt.executeQuery("SELECT FOODNAME FROM FOOD;");
                                  }
                                  catch (Exception e)
                                  {System.out.println("query exception");}
                                  dumpResults("--Contents of FoodName column--");
                                  //嘗試實(shí)際的 SQL 語(yǔ)句
                                  try
                                  {
                                  Statement stmt = con.createStatement();
                                  results = stmt.executeQuery(query);
                                  }
                                  catch (Exception e)
                                  {System.out.println("query exception");}
                                  dumpResults("--Results of Query--");
                                  }
                                  

      該程序打印出的結(jié)果如下所示:

              C:\Projects\objectJava\chapter19>java JdbcOdbc_test
                                  Connected to:jdbc:odbc:Grocery prices
                                  Driver JDBC-ODBC Bridge (ODBCJT32.DLL)
                                  --Tables--
                                  TABLE_QUALIFIER TABLE_OWNER TABLE_NAME TABLE_TYPE REMARKS
                                  groceries null Food TABLE null
                                  groceries null FoodPrice TABLE null
                                  groceries null Stores TABLE null
                                  --Column Names--
                                  FSKey StoreKey FoodKey Price
                                  --Contents of FoodName column--
                                  FOODNAME
                                  Apples
                                  Oranges
                                  Hamburger
                                  Butter
                                  Milk
                                  Cola
                                  Green beans
                                  --Results of Query--
                                  FoodName
                                  Cola
                                  

      構(gòu)建更高級(jí)別的JDBC對(duì)象

      從上面的例子可以明顯看出,如果可以將我們使用過(guò)的一些方法封裝在幾個(gè)更高級(jí)別對(duì)象中,那將非常有幫助,我們不僅可以封裝 try 程序塊,而且可以更簡(jiǎn)單地訪問(wèn) ResultSet 方法。

      在這一部分中,我們將構(gòu)建一個(gè)新的 resultSet 對(duì)象,該對(duì)象封裝了JDBC ResultSet 對(duì)象,并以String數(shù)組的形式返回一行數(shù)據(jù)。我們發(fā)現(xiàn)您始終需要從 ResultSetMetaData 對(duì)象中獲取列的序號(hào)和名稱,因此,創(chuàng)建一個(gè)封裝元數(shù)據(jù)的新對(duì)象就非常合理。

      另外,我們經(jīng)常需要按名稱或整數(shù)索引提取某行的元素,如果不必總是將這些訪問(wèn)語(yǔ)句包括 try 塊中,那將大有幫助。最后一點(diǎn),如果我們需要整行的內(nèi)容,則更方便的做法是將整行以String數(shù)組形式返回。在下面所示的 resultSet 對(duì)象中,我們致力于實(shí)現(xiàn)這些目標(biāo):

              class resultSet
                                  {
                                  //
                                  這個(gè)類是
                                  JDBC ResultSet
                                  對(duì)象的更高級(jí)抽象
                                  ResultSet rs;
                                  ResultSetMetaData rsmd;
                                  int numCols;
                                  public resultSet(ResultSet rset)
                                  {
                                  rs = rset;
                                  try
                                  {
                                  //
                                  同時(shí)獲取元數(shù)據(jù)和列數(shù)
                                  rsmd = rs.getMetaData();
                                  numCols = rsmd.getColumnCount();
                                  }
                                  catch (Exception e)
                                  {System.out.println("resultset error"
                                  +e.getMessage());}
                                  }
                                  //--
                                  public String[] getMetaData()
                                  {
                                  //
                                  返回包含所有列名或其他元數(shù)據(jù)的
                                  //
                                  一個(gè)數(shù)組
                                  String md[] = new String[numCols];
                                  try
                                  {
                                  for (int i=1; i<= numCols; i++)
                                  md[i-1] = rsmd.getColumnName(i);
                                  }
                                  catch (Exception e)
                                  {System.out.println("meta data error"+
                                  e.getMessage());}
                                  return md;
                                  }
                                  //--
                                  public boolean hasMoreElements()
                                  {
                                  try{
                                  return rs.next();
                                  }
                                  catch(Exception e){return false;}
                                  }
                                  //--
                                  public String[] nextElement()
                                  {
                                  //
                                  將行的內(nèi)容復(fù)制到字符串?dāng)?shù)組中
                                  String[] row = new String[numCols];
                                  try
                                  {
                                  for (int i = 1; i <= numCols; i++)
                                  row[i-1] = rs.getString(i);
                                  }
                                  catch (Exception e)
                                  {System.out.println("next element error"+
                                  e.getMessage());}
                                  return row;
                                  }
                                  //--
                                  public String getColumnValue(String columnName)
                                  {
                                  String res = "";
                                  try
                                  {
                                  res = rs.getString(columnName);
                                  }
                                  catch (Exception e)
                                  {System.out.println("Column value error:"+
                                  columnName+e.getMessage());}
                                  return res;
                                  }
                                  //--
                                  public String getColumnValue(int i)
                                  {
                                  String res = "";
                                  try
                                  {
                                  res = rs.getString(i);
                                  }
                                  catch (Exception e)
                                  {System.out.println("Column value error:"+
                                  columnName+e.getMessage());}
                                  return res;
                                  }
                                  //--
                                  public void finalize()
                                  {
                                  try{rs.close();}
                                  catch (Exception e)
                                  {System.out.println(e.getMessage());}
                                  }
                                  }
                                  

      通過(guò)簡(jiǎn)單使用 new 操作符就地創(chuàng)建一個(gè) ResultSet 對(duì)象,我們很容易將任何 ResultSet 對(duì)象封裝在此類中:

              ResultSet results = .. //
                                  按通常的方法獲得
                                  ResultsSet
                                  //
                                  利用它創(chuàng)建一個(gè)更有用的對(duì)象
                                  resultSet rs = new resultSet(results);
                                  

      并很容易在任何 JDBC 程序中使用這個(gè)對(duì)象。

      構(gòu)建一個(gè)Database對(duì)象

      我們沿 00 鏈向上移的另一部分努力是創(chuàng)建一個(gè) Database 對(duì)象,它將封裝下列對(duì)象的行為: Connection 、 Statement DatabaseMetaData 對(duì)象, 以及我們剛剛構(gòu)建的 SQL 查詢和 resultSet 。我們的 Database 對(duì)象允許我們創(chuàng)建連接、獲取表名、在數(shù)據(jù)庫(kù)中移動(dòng)以及更簡(jiǎn)單地獲得行和列的值。請(qǐng)注意, Execute 方法返回一個(gè) resultSet 對(duì)象,您可以直接對(duì)它進(jìn)行操作。

              class Database
                                  {
                                  //
                                  這是一個(gè)將
                                  JDBC
                                  數(shù)據(jù)庫(kù)的所有功能封裝在單個(gè)對(duì)象中的類
                                  Connection con;
                                  resultSet results;
                                  ResultSetMetaData rsmd;
                                  DatabaseMetaData dma;
                                  String catalog;
                                  String types[];
                                  public Database(String driver)
                                  {
                                  types = new String[1];
                                  types[0] = "TABLES"; //
                                  初始化類型
                                  try{Class.forName(driver);} //
                                  加載
                                  JDBC-ODBC
                                  橋驅(qū)動(dòng)程序
                                  catch (Exception e)
                                  {System.out.println(e.getMessage());}
                                  }
                                  //--
                                  public void Open(String url, String cat)
                                  {
                                  catalog = cat;
                                  try {con = DriverManager.getConnection(url);
                                  dma =con.getMetaData(); //
                                  獲取元數(shù)據(jù)
                                  }
                                  catch (Exception e)
                                  {System.out.println(e.getMessage());}
                                  }
                                  //--
                                  public String[] getTableNames()
                                  {
                                  String[] tbnames = null;
                                  Vector tname = new Vector();
                                  //
                                  將表名添加到一個(gè) Vector
                                  中,
                                  //
                                  因?yàn)槲覀儾恢烙卸嗌賯€(gè)表
                                  try {
                                  results =
                                  new resultSet(dma.getTables(catalog, null,
                                  "%", types));
                                  while (results.hasMoreElements())
                                  tname.addElement(results.getColumnValue("TABLE_NAME"));
                                  }
                                  catch (Exception e) {System.out.println(e);}
                                  //
                                  將表名復(fù)制到一個(gè)
                                  String
                                  數(shù)組中
                                  tbnames = new String[tname.size()];
                                  for (int i=0; i< tname.size(); i++)
                                  tbnames[i] = (String)tname.elementAt(i);
                                  return tbnames;
                                  }
                                  //--
                                  public String[] getTableMetaData()
                                  {
                                  //
                                  返回表類型的信息
                                  results = null;
                                  try{
                                  results =
                                  new resultSet(dma.getTables(catalog, null,
                                  "%", types));
                                  }
                                  catch (Exception e)
                                  {System.out.println(e.getMessage());}
                                  return results.getMetaData();
                                  }
                                  //--
                                  public String[] getColumnMetaData(String tablename)
                                  {
                                  //
                                  返回一個(gè)列的數(shù)據(jù)
                                  results = null;
                                  try {
                                  results =
                                  new resultSet(dma.getColumns(catalog, null,
                                  tablename, null));
                                  }
                                  catch (Exception e)
                                  {System.out.println(e.getMessage());}
                                  return results.getMetaData();
                                  }
                                  //--
                                  public String[] getColumnNames(String table)
                                  {
                                  //
                                  返回一個(gè)列名數(shù)組
                                  String[] tbnames = null;
                                  Vector tname = new Vector();
                                  try {
                                  results =
                                  new resultSet(dma.getColumns(catalog, null,
                                  table, null));
                                  while (results.hasMoreElements() )
                                  tname.addElement(results.getColumnValue("COLUMN_NAME"));
                                  }
                                  catch (Exception e) {System.out.println(e);}
                                  tbnames = new String[tname.size()];
                                  for (int i=0; i< tname.size(); i++)
                                  tbnames[i] = (String)tname.elementAt(i);
                                  return tbnames;
                                  }
                                  //--
                                  public String getColumnValue(String table,
                                  String columnName)
                                  {
                                  //
                                  返回給定列的值
                                  String res = null;
                                  try
                                  {
                                  if (table.length()>0)
                                  results =
                                  Execute("Select " + columnName +
                                  " from " + table +
                                  " order by "+columnName);
                                  if (results.hasMoreElements())
                                  res = results.getColumnValue(columnName);
                                  }
                                  catch (Exception e)
                                  {System.out.println("Column value error" +
                                  columnName+ e.getMessage());}
                                  return res;
                                  }
                                  //--
                                  public String getNextValue(String columnName)
                                  {
                                  //
                                  使用存儲(chǔ)的
                                  resultSet
                                  //
                                  返回該列的下一個(gè)值
                                  String res = "";
                                  try
                                  {
                                  if (results.hasMoreElements())
                                  res = results.getColumnValue(columnName);
                                  }
                                  catch (Exception e)
                                  {System.out.println("next value error"+
                                  columnName+ e.getMessage());}
                                  return res;
                                  }
                                  //--
                                  public resultSet Execute(String sql)
                                  {
                                  //
                                  對(duì)此數(shù)據(jù)庫(kù)執(zhí)行一個(gè)
                                  SQL
                                  查詢
                                  results = null;
                                  try
                                  {
                                  Statement stmt = con.createStatement();
                                  results = new resultSet(stmt.executeQuery(sql));
                                  }
                                  catch (Exception e)
                                  {System.out.println("execute error"+
                                  e.getMessage());}
                                  return results;
                                  }
                                  }
                                  

      一個(gè)可視化的數(shù)據(jù)庫(kù)程序

      為了對(duì)我們本章學(xué)習(xí)的內(nèi)容進(jìn)行總結(jié),我們編寫(xiě)一個(gè)簡(jiǎn)單的 GUI 程序,它可以顯示數(shù)據(jù)庫(kù)的表名、列名和列內(nèi)容。我們還將包括一個(gè)文本區(qū)域,您可以在其中鍵入一個(gè)要對(duì)數(shù)據(jù)庫(kù)執(zhí)行的 SQL 查詢。在 Companion CD-ROM 上的 \chapter20 子目錄中,可以找到本程序(稱為 dbFrame.java )所使用的 resultSet Database 類。程序的顯示界面如圖 3 所示。


      數(shù)據(jù)庫(kù)圖示
      圖3:用來(lái)顯示用JDBC連接的數(shù)據(jù)庫(kù)中的數(shù)據(jù)的dbFrame.java程序。

      在本程序中,默認(rèn)數(shù)據(jù)庫(kù)(groceries.mdb)的表名顯示在左側(cè)的欄中。當(dāng)您單擊其中一個(gè)表名時(shí),列名就會(huì)顯示在中間的欄中。最后,當(dāng)您單擊中間欄中的某一行時(shí),該行的內(nèi)容就會(huì)顯示在右側(cè)的欄中。

      本程序的關(guān)鍵只是接收列表選擇,然后清除并填充正確的列表框:

              public void itemStateChanged(ItemEvent e)
                                  {
                                  Object obj = e.getSource();
                                  if (obj == Tables) //
                                  放入列名
                                  showColumns();
                                  if (obj == Columns) //
                                  放入列的內(nèi)容
                                  showData();
                                  }
                                  //--
                                  private void loadList(List list, String[] s)
                                  {
                                  //
                                  清除并填充指定的列表框
                                  list.removeAll();
                                  for (int i=0; i< s.length; i++)
                                  list.add(s[i]);
                                  }
                                  //--
                                  private void showColumns()
                                  {
                                  //
                                  顯示列名
                                  String cnames[] =
                                  db.getColumnNames(Tables.getSelectedItem());
                                  loadList(Columns, cnames);
                                  }
                                  //--
                                  private void showData()
                                  {
                                  String colname = Columns.getSelectedItem();
                                  String colval =
                                  db.getColumnValue(Tables.getSelectedItem(),
                                  colname);
                                  Data.setVisible(false);
                                  Data.removeAll();
                                  Data.setVisible(true);
                                  colval =
                                  db.getNextValue(Columns.getSelectedItem());
                                  while (colval.length()>0)
                                  {
                                  Data.add(colval);
                                  colval =
                                  db.getNextValue(Columns.getSelectedItem());
                                  }
                                  }
                                  

      執(zhí)行查詢

      顯示畫(huà)面底部的文本區(qū)域使您可鍵入所需的任何 SQL 查詢。演示程序中構(gòu)建的一個(gè)查詢?nèi)缦滤荆?/p>

              String queryText =
                                  "SELECT DISTINCTROW FoodName, StoreName, Price "+
                                  "FROM (Food INNER JOIN FoodPrice ON "+
                                  "Food.FoodKey = FoodPrice.FoodKey) " +
                                  "INNER JOIN Stores ON "+
                                  "FoodPrice.StoreKey = Stores.StoreKey "+
                                  "WHERE (((Food.FoodName)=\‘Oranges\‘)) "+
                                  " ORDER BY FoodPrice.Price;";
                                  

      此查詢簡(jiǎn)單地列出每個(gè)雜貨店的桔子價(jià)格。

      當(dāng)您單擊 Run Query按鈕時(shí),它將執(zhí)行此查詢,并將resultSet對(duì)象傳送給一個(gè)對(duì)話框進(jìn)行顯示:

              public void actionPerformed(ActionEvent e)
                                  {
                                  Object obj = e.getSource();
                                  if (obj == Quit)
                                  System.exit(0);
                                  if (obj == Search)
                                  clickedSearch();
                                  }
                                  //--
                                  private void clickedSearch()
                                  {
                                  resultSet rs = db.Execute(query.getText());
                                  String cnames[] = rs.getMetaData();
                                  queryDialog q = new queryDialog(this, rs);
                                  q.show();
                                  }
                                  

      查詢結(jié)果對(duì)話框

      查詢對(duì)話框獲得 resultSet 對(duì)象,并將每一行放入一個(gè) String 數(shù)組中,然后將這些 String 數(shù)組放入一個(gè) Vector 中,這樣就可以在 paint() 子程序運(yùn)行期間快速訪問(wèn)這些行。

              private void makeTables()
                                  {
                                  //
                                  將每一行放入一個(gè)
                                  String
                                  數(shù)組中,并將
                                  //
                                  這些字符串?dāng)?shù)組全部放入一個(gè)
                                  Vector
                                  中
                                  tables = new Vector();
                                  String t[] = results.getMetaData();
                                  tables.addElement( t);
                                  while (results.hasMoreElements())
                                  tables.addElement(results.nextElement());
                                  }
                                  

      我們通過(guò) Graphics 的 drawString() 方法將數(shù)據(jù)繪制在一個(gè) Panel 中。就像在 Printer 對(duì)象中一樣,我們必須自己跟蹤 x 和 y 的位置。

              public void paint(Graphics g)
                                  {
                                  String s[];
                                  int x=0;
                                  //
                                  計(jì)算字體的高度
                                  int y =g.getFontMetrics().getHeight();
                                  //
                                  估算列的高度
                                  int deltaX = (int)1.5f*
                                  (g.getFontMetrics().stringWidth("wwwwwwwwwwwwww"));
                                  //
                                  遍歷表矢量
                                  for (int i=0; i< tables.size(); i++)
                                  {
                                  s = (String[])tables.elementAt(i);
                                  //
                                  繪制字符串?dāng)?shù)組中的每一行
                                  for (int j =0; j< s.length; j++)
                                  {
                                  String st= s[j];
                                  g.drawString(st, x, y);
                                  x += deltaX; //
                                  移到下一列
                                  }
                                  x = 0; //
                                  開(kāi)始一個(gè)新行
                                  y += g.getFontMetrics().getHeight();
                                  //
                                  列標(biāo)簽與列數(shù)據(jù)之間的額外空間
                                  if (i == 0) y += g.getFontMetrics().getHeight();
                                  }
                                  }
                                  

      內(nèi)建查詢的 queryDialog 如圖 4 所示。


      查詢結(jié)果
      圖4:dbFrame程序中 顯示的queryDialog,其中顯示的是默認(rèn)查詢的結(jié)果。

      示例文件

      groceries.zip
      dbFrame.zip
      jdbc-odbc Bridge

      小結(jié)

      在本文中,我們討論了數(shù)據(jù)庫(kù)以及檢驗(yàn)數(shù)據(jù)庫(kù)并對(duì)數(shù)據(jù)庫(kù)執(zhí)行查詢的方法。我們已經(jīng)看到, JDBC 提供了一種與平臺(tái)和數(shù)據(jù)庫(kù)無(wú)關(guān)的、面向?qū)ο蟮姆椒▉?lái)訪問(wèn)這些數(shù)據(jù),我們還學(xué)習(xí)了 JDBC 的主要對(duì)象: ResultSet 、 ResultSetMetaData DatabaseMetaData。 在用這些對(duì)象編寫(xiě)了一個(gè)簡(jiǎn)單的程序之后,我們?cè)O(shè)計(jì)了更高級(jí)別的 resultSet Database 對(duì)象,我們用它們構(gòu)建了一個(gè)簡(jiǎn)單的可視化界面來(lái)顯示數(shù)據(jù)庫(kù)信息。

      如果您熟悉數(shù)據(jù)庫(kù)的強(qiáng)大功能,就會(huì)認(rèn)識(shí)到SQL語(yǔ)言可使您執(zhí)行比我們此處所述操作更強(qiáng)大的任務(wù)。例如,您可以創(chuàng)建新表、添加、更改或刪除表的行、列或單個(gè)表元。使用JDBC,所有這一切都變得通用和易于處理。

      如果您使用的是特定平臺(tái)的數(shù)據(jù)庫(kù)驅(qū)動(dòng)程序,如JDBC-ODBCBridge,則您在編寫(xiě)應(yīng)用程序時(shí)會(huì)受到限制,因?yàn)閍pplet不能連接在另一臺(tái)計(jì)算機(jī)上運(yùn)行的這個(gè)橋。其他客戶機(jī)-服務(wù)器數(shù)據(jù)庫(kù),如IBM的DB2,允許您使用applet中的JDBC與其連接。



      關(guān)于作者

       

      IBM has authored this article

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多