<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 15.7 用JDBC連接數據庫 據估算,將近一半的軟件開發都要涉及客戶(機)/服務器方面的操作。Java為自己保證的一項出色能力就是構建與平臺無關的客戶端/服務器數據庫應用。在Java 1.1中,這一保證通過Java數據庫連接(JDBC)實現了。 數據庫最主要的一個問題就是各家公司之間的規格大戰。確實存在一種“標準”數據庫語言,即“結構查詢語言”(SQL-92),但通常都必須確切知道自己要和哪家數據庫公司打交道,否則極易出問題,盡管存在所謂的“標準”。JDBC是面向“與平臺無關”設計的,所以在編程的時候不必關心自己要使用的是什么數據庫產品。然而,從JDBC里仍有可能發出對某些數據庫公司專用功能的調用,所以仍然不可任性妄為。 和Java中的許多API一樣,JDBC也做到了盡量的簡化。我們發出的方法調用對應于從數據庫收集數據時想當然的做法:同數據庫連接,創建一個語句并執行查詢,然后處理結果集。 為實現這一“與平臺無關”的特點,JDBC為我們提供了一個“驅動程序管理器”,它能動態維護數據庫查詢所需的所有驅動程序對象。所以假如要連接由三家公司開發的不同種類的數據庫,就需要三個單獨的驅動程序對象。驅動程序對象會在裝載時由“驅動程序管理器”自動注冊,并可用`Class.forName()`強行裝載。 為打開一個數據庫,必須創建一個“數據庫URL”,它要指定下述三方面的內容: (1) 用`jdbc`指出要使用JDBC。 (2) “子協議”:驅動程序的名字或者一種數據庫連接機制的名稱。由于JDBC的設計從ODBC吸收了許多靈感,所以可以選用的第一種子協議就是“jdbc-odbc橋”,它用`odbc`關鍵字即可指定。 (3) 數據庫標識符:隨使用的數據庫驅動程序的不同而變化,但一般都提供了一個比較符合邏輯的名稱,由數據庫管理軟件映射(對應)到保存了數據表的一個物理目錄。為使自己的數據庫標識符具有任何含義,必須用自己的數據庫管理軟件為自己喜歡的名字注冊(注冊的具體過程又隨運行平臺的不同而變化)。 所有這些信息都統一編譯到一個字符串里,即“數據庫URL”。舉個例子來說,若想通過ODBC子協議同一個標識為`people`的數據庫連接,相應的數據庫URL可設為: ``` String dbUrl = "jdbc:odbc:people" ``` 如果通過一個網絡連接,數據庫URL也需要包含對遠程機器進行標識的信息。 準備好同數據庫連接后,可調用靜態方法`DriverManager.getConnection()`,將數據庫的URL以及進入那個數據庫所需的用戶名密碼傳遞給它。得到的返回結果是一個`Connection`對象,利用它即可查詢和操縱數據庫。 下面這個例子將打開一個聯絡信息數據庫,并根據命令行提供的參數查詢一個人的姓(Last Name)。它只選擇那些有E-mail地址的人的名字,然后列印出符合查詢條件的所有人: ``` //: Lookup.java // Looks up email addresses in a // local database using JDBC import java.sql.*; public class Lookup { public static void main(String[] args) { String dbUrl = "jdbc:odbc:people"; String user = ""; String password = ""; try { // Load the driver (registers itself) Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver"); Connection c = DriverManager.getConnection( dbUrl, user, password); Statement s = c.createStatement(); // SQL code: ResultSet r = s.executeQuery( "SELECT FIRST, LAST, EMAIL " + "FROM people.csv people " + "WHERE " + "(LAST='" + args[0] + "') " + " AND (EMAIL Is Not Null) " + "ORDER BY FIRST"); while(r.next()) { // Capitalization doesn't matter: System.out.println( r.getString("Last") + ", " + r.getString("fIRST") + ": " + r.getString("EMAIL") ); } s.close(); // Also closes ResultSet } catch(Exception e) { e.printStackTrace(); } } } ///:~ ``` 可以看到,數據庫URL的創建過程與我們前面講述的完全一樣。在該例中,數據庫未設密碼保護,所以用戶名和密碼都是空串。 用`DriverManager.getConnection()`建好連接后,接下來可根據結果`Connection`對象創建一個`Statement`(語句)對象,這是用`createStatement()`方法實現的。根據結果`Statement`,我們可調用`executeQuery()`,向其傳遞包含了SQL-92標準SQL語句的一個字符串(不久就會看到如何自動創建這類語句,所以沒必要在這里知道關于SQL更多的東西)。 `executeQuery()`方法會返回一個`ResultSet`(結果集)對象,它與迭代器非常相似:`next()`方法將迭代器移至語句中的下一條記錄;如果已抵達結果集的末尾,則返回`null`。我們肯定能從`executeQuery()`返回一個`ResultSet`對象,即使查詢結果是個空集(也就是說,不會產生一個異常)。注意在試圖讀取任何記錄數據之前,都必須調用一次`next()`。若結果集為空,那么對`next()`的這個首次調用就會返回`false`。對于結果集中的每條記錄,都可將字段名作為字符串使用(當然還有其他方法),從而選擇不同的字段。另外要注意的是字段名的大小寫是無關緊要的——SQL數據庫不在乎這個問題。為決定返回的類型,可調用`getString()`,`getFloat()`等等。到這個時候,我們已經用Java的原始格式得到了自己的數據庫數據,接下去可用Java代碼做自己想做的任何事情了。 ## 15.7.1 讓示例運行起來 就JDBC來說,代碼本身是很容易理解的。最令人迷惑的部分是如何使它在自己特定的系統上運行起來。之所以會感到迷惑,是由于它要求我們掌握如何才能使JDBC驅動程序正確裝載,以及如何用我們的數據庫管理軟件來設置一個數據庫。 當然,具體的操作過程在不同的機器上也會有所區別。但這兒提供的在32位Windows環境下操作過程可有效幫助大家理解在其他平臺上的操作。 (1) 步驟1:尋找JDBC驅動程序 上述程序包含了下面這條語句: ``` Class.forName("sun.jdbc.odbc.JdbcOdbcDriver"); ``` 這似乎暗示著一個目錄結構,但大家不要被它蒙騙了。在我手上這個JDK 1.1安裝版本中,根本不存在叫作`JdbcOdbcDriver.class`的一個文件。所以假如在看了這個例子后去尋找它,那么必然會徒勞而返。另一些人提供的例子使用的是一個假名字,如`myDriver.ClassName`,但人們從字面上得不到任何幫助。事實上,上述用于裝載jdbc-odbc驅動程序(實際是與JDK 1.1配套提供的唯一驅動)的語句在聯機文檔的多處地方均有出現(特別是在一個標記為“JDBC-ODBC Bridge Driver”的頁內)。若上面的裝載語句不能工作,那么它的名字可能已隨著Java新版本的發布而改變了;此時應到聯機文檔里尋找新的表述方式。 若裝載語句出錯,會在這個時候得到一個異常。為了檢驗驅動程序裝載語句是不是能正常工作,請將該語句后面直到`catch`從句之間的代碼暫時設為注釋。如果程序運行時未出現異常,表明驅動程序的裝載是正確的。 (2) 步驟2:配置數據庫 同樣地,我們只限于在32位Windows環境中工作;您可能需要研究一下自己的操作系統,找出適合自己平臺的配置方法。 首先打開控制面板。其中可能有兩個圖標都含有“ODBC”字樣,必須選擇那個“32位ODBC”,因為另一個是為了保持與16位軟件的向后兼容而設置的,和JDBC混用沒有任何結果。雙擊“32位ODBC”圖標后,看到的應該是一個卡片式對話框,上面一排有多個卡片標簽,其中包括“用戶DSN”、“系統DSN”、“文件DSN”等等。其中,“DSN”代表“數據源名稱”(Data Source Name)。它們都與JDBC-ODBC橋有關,但設置數據庫時唯一重要的地方“系統DSN”。盡管如此,由于需要測試自己的配置以及創建查詢,所以也需要在“文件DSN”中設置自己的數據庫。這樣便可讓Microsoft Query工具(與Microsoft Office配套提供)正確地找到數據庫。注意一些軟件公司也設計了自己的查詢工具。 最有趣的數據庫是我們已經使用過的一個。標準ODBC支持多種文件格式,其中包括由不同公司專用的一些格式,如dBASE。然而,它也包括了簡單的“逗號分隔ASCII”格式,它幾乎是每種數據工具都能夠生成的。就目前的例子來說,我只選擇自己的`people`數據庫。這是我多年來一直在維護的一個數據庫,中間使用了各種聯絡管理工具。我把它導出成為一個逗號分隔的ASCII文件(一般有個`.csv`擴展名,用Outlook Express導出通信簿時亦可選用同樣的文件格式)。在“文件DSN”區域,我按下“添加”按鈕,選擇用于控制逗號分隔ASCII文件的文本驅動程序(Microsoft Text Driver),然后撤消對“使用當前目錄”的選擇,以便導出數據文件時可以自行指定目錄。 大家會注意到在進行這些工作的時候,并沒有實際指定一個文件,只是一個目錄。那是因為數據庫通常是由某個目錄下的一系列文件構成的(盡管也可能采用其他形式)。每個文件一般都包含了單個“數據表”,而且SQL語句可以產生從數據庫中多個表摘取出來的結果(這叫作“聯合”,或者`join`)只包含了單張表的數據庫(就象目前這個)通常叫作“平面文件數據庫”。對于大多數問題,如果已經超過了簡單的數據存儲與獲取力所能及的范圍,那么必須使用多個數據表。通過“聯合”,從而獲得希望的結果。我們把這些叫作“關系型”數據庫。 (3) 步驟3:測試配置 為了對配置進行測試,需用一種方式核實數據庫是否可由查詢它的一個程序“見到”。當然,可以簡單地運行上述的JDBC示范程序,并加入下述語句: ``` Connection c = DriverManager.getConnection( dbUrl, user, password); ``` 若拋出一個異常,表明你的配置有誤。 然而,此時很有必要使用一個自動化的查詢生成工具。我使用的是與Microsoft Office配套提供的Microsoft Query,但你完全可以自行選擇一個。查詢工具必須知道數據庫在什么地方,而Microsoft Query要求我進入ODBC Administrator的“文件DSN”卡片,并在那里新添一個條目。同樣指定文本驅動程序以及保存數據庫的目錄。雖然可將這個條目命名為自己喜歡的任何東西,但最好還是使用與“系統DSN”中相同的名字。 做完這些工作后,再用查詢工具創建一個新查詢時,便會發現自己的數據庫可以使用了。 (4) 步驟4:建立自己的SQL查詢 我用Microsoft Query創建的查詢不僅指出目標數據庫存在且次序良好,也會自動生成SQL代碼,以便將其插入我自己的Java程序。我希望這個查詢能夠檢查記錄中是否存在與啟動Java程序時在命令行鍵入的相同的“姓”(Last Name)。所以作為一個起點,我搜索自己的姓`Eckel`。另外,我希望只顯示出有對應E-mail地址的那些名字。創建這個查詢的步驟如下: (1) 啟動一個新查詢,并使用查詢向導(Query Wizard)。選擇`people`數據庫(等價于用適應的數據庫URL打開數據庫連接)。 (2) 選擇數據庫中的`people`表。從這張數據表中,選擇`FIRST`,`LAST`和`EMAIL`列。 (3) 在“Filter Data”(過濾器數據庫)下,選擇`LAST`,并選擇`equals`(等于),加上參數`Eckel`。點選“And”單選鈕。 (4) 選擇`EMAIL`,并選中“Is not Null”(不為空)。 (5) 在“Sort By”下,選擇`FIRST`。 查詢結果會向我們展示出是否能得到自己希望的東西。 現在可以按下SQL按鈕。不需要我們任何方面的介入,正確的SQL代碼會立即彈現出來,以便我們粘貼和復制。對于這個查詢,相應的SQL代碼如下: ``` SELECT people.FIRST, people.LAST, people.EMAIL FROM people.csv people WHERE (people.LAST='Eckel') AND (people.EMAIL Is Not Null) ORDER BY people.FIRST ``` 若查詢比較復雜,手工編碼極易出錯。但利用一個查詢工具,就可以交互式地測試自己的查詢,并自動獲得正確的代碼。事實上,親手為這些事情編碼是難以讓人接受的。 (5) 步驟5:在自己的查詢中修改和粘貼 我們注意到上述代碼與程序中使用的代碼是有所區別的。那是由于查詢工具對所有名字都進行了限定,即便涉及的僅有一個數據表(若真的涉及多個數據表,這種限定可避免來自不同表的同名數據列發生沖突)。由于這個查詢只需要用到一個數據表,所以可考慮從大多數名字中刪除“people”限定符,就象下面這樣: ``` SELECT FIRST, LAST, EMAIL FROM people.csv people WHERE (LAST='Eckel') AND (EMAIL Is Not Null) ORDER BY FIRST ``` 此外,我們不希望“硬編碼”這個程序,從而只能查找一個特定的名字。相反,它應該能查找我們在命令行動態提供的一個名字。所以還要進行必要的修改,并將SQL語句轉換成一個動態生成的字符串。如下所示: ``` "SELECT FIRST, LAST, EMAIL " + "FROM people.csv people " + "WHERE " + "(LAST='" + args[0] + "') " + " AND (EMAIL Is Not Null) " + "ORDER BY FIRST"); ``` SQL還有一種方式可將名字插入一個查詢,名為“過程”(`Procedures`),它的速度非常快。但對于我們的大多數實驗性數據庫操作,以及一些初級應用,用Java構建查詢字符串已經很不錯了。 從這個例子可以看出,利用目前找得到的工具——特別是查詢構建工具——涉及SQL及JDBC的數據庫編程是非常簡單和直觀的。 ## 15.7.2 查找程序的GUI版本 最好的方法是讓查找程序一直保持運行,要查找什么東西時只需簡單地切換到它,并鍵入要查找的名字即可。下面這個程序將查找程序作為一個“application/applet”創建,且添加了名字自動填寫功能,所以不必鍵入完整的姓,即可看到數據: ``` //: VLookup.java // GUI version of Lookup.java import java.awt.*; import java.awt.event.*; import java.applet.*; import java.sql.*; public class VLookup extends Applet { String dbUrl = "jdbc:odbc:people"; String user = ""; String password = ""; Statement s; TextField searchFor = new TextField(20); Label completion = new Label(" "); TextArea results = new TextArea(40, 20); public void init() { searchFor.addTextListener(new SearchForL()); Panel p = new Panel(); p.add(new Label("Last name to search for:")); p.add(searchFor); p.add(completion); setLayout(new BorderLayout()); add(p, BorderLayout.NORTH); add(results, BorderLayout.CENTER); try { // Load the driver (registers itself) Class.forName( "sun.jdbc.odbc.JdbcOdbcDriver"); Connection c = DriverManager.getConnection( dbUrl, user, password); s = c.createStatement(); } catch(Exception e) { results.setText(e.getMessage()); } } class SearchForL implements TextListener { public void textValueChanged(TextEvent te) { ResultSet r; if(searchFor.getText().length() == 0) { completion.setText(""); results.setText(""); return; } try { // Name completion: r = s.executeQuery( "SELECT LAST FROM people.csv people " + "WHERE (LAST Like '" + searchFor.getText() + "%') ORDER BY LAST"); if(r.next()) completion.setText( r.getString("last")); r = s.executeQuery( "SELECT FIRST, LAST, EMAIL " + "FROM people.csv people " + "WHERE (LAST='" + completion.getText() + "') AND (EMAIL Is Not Null) " + "ORDER BY FIRST"); } catch(Exception e) { results.setText( searchFor.getText() + "\n"); results.append(e.getMessage()); return; } results.setText(""); try { while(r.next()) { results.append( r.getString("Last") + ", " + r.getString("fIRST") + ": " + r.getString("EMAIL") + "\n"); } } catch(Exception e) { results.setText(e.getMessage()); } } } public static void main(String[] args) { VLookup applet = new VLookup(); Frame aFrame = new Frame("Email lookup"); aFrame.addWindowListener( new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } }); aFrame.add(applet, BorderLayout.CENTER); aFrame.setSize(500,200); applet.init(); applet.start(); aFrame.setVisible(true); } } ///:~ ``` 數據庫的許多邏輯都是相同的,但大家可看到這里添加了一個`TextListener`,用于監視在`TextField`(文本字段)的輸入。所以只要鍵入一個新字符,它首先就會試著查找數據庫中的“姓”,并顯示出與當前輸入相符的第一條記錄(將其置入`completion Label`,并用它作為要查找的文本)。因此,只要我們鍵入了足夠的字符,使程序能找到與之相符的唯一一條記錄,就可以停手了。 ## 15.7.3 JDBC API為何如何復雜 閱覽JDBC的聯機幫助文檔時,我們往往會產生畏難情緒。特別是`DatabaseMetaData`接口——與Java中看到的大多數接口相反,它的體積顯得非常龐大——存在著數量眾多的方法,比如`dataDefinitionCausesTransactionCommit()`,`getMaxColumnNameLength()`,`getMaxStatementLength()`,`storesMixedCaseQuotedIdentifiers()`,`supportsANSI92IntermediateSQL()`,`supportsLimitedOuterJoins()`等等。它們有這兒有什么意義嗎? 正如早先指出的那樣,數據庫起初一直處于一種混亂狀態。這主要是由于各種數據庫應用提出的要求造成的,所以數據庫工具顯得非常“強大”——換言之,“龐大”。只是近幾年才涌現出了SQL的通用語言(常用的還有其他許多數據庫語言)。但即便象SQL這樣的“標準”,也存在無數的變種,所以JDBC必須提供一個巨大的`DatabaseMetaData`接口,使我們的代碼能真正利用當前要連接的一種“標準”SQL數據庫的能力。簡言之,我們可編寫出簡單的、能移植的SQL。但如果想優化代碼的執行速度,那么為了適應不同數據庫類型的特點,我們的編寫代碼的麻煩就大了。 當然,這并不是Java的缺陷。數據庫產品之間的差異是我們和JDBC都要面對的一個現實。但是,如果能編寫通用的查詢,而不必太關心性能,那么事情就要簡單得多。即使必須對性能作一番調整,只要知道最終面向的平臺,也不必針對每一種情況都編寫不同的優化代碼。 在Sun發布的Java 1.1產品中,配套提供了一系列電子文檔,其中有對JDBC更全面的介紹。此外,在由Hamilton Cattel和Fisher編著、Addison-Wesley于1997年出版的《JDBC Database Access with Java》中,也提供了有關這一主題的許多有用資料。同時,書店里也經常出現一些有關JDBC的新書。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看