2012年9月26日 星期三

利用純 JDBC 驅動程式來存取資料庫

MySQL Server 簡介

The materials presented in this web page is provided as is and is used solely for educational purpose. Use at your own risks.
Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu

請勿轉貼
看其他教材

本文假設你已經安裝了 MySQL Server 5.1.x 版,而且你也依據之前的說明, 建立了使用者 jlu,而且你也為 jlu 建立了一個資料庫 eric,並且在資料庫中, 建立了表格 Product。在下列的步驟中,我們將說明如何利用純 JDBC 驅動程式 來開發 Java 程式以便於對表格 Product 進行增、刪、改、查的動作。 以下文件,我們假設讀者熟析 Java 程式;如果讀者想學習 Java 的物件導向 設計的技巧,我們建議購買作者所寫的 呂瑞麟與陳宜惠著,Java 101: 物件導向程式設計,上奇出版,09/2008 以及其 勘誤表
  1. 為了讓 Java 程式(包含 JSP、Java Servlets 等)能夠存取資料庫, 昇陽(Sun) 定義了 JDBC 的介面,而各家的資料庫管理系統可以依據這些介面定義, 開發出其資料庫系統的 JDBC 驅動程式。JDBC 驅動程式又分成四大類,其細節 可以參考 資料處理入門,在本文中,我們只針對 MySQL 提供的純 JDBC 驅動程式來說明。
  2. 純 JDBC 驅動程式:若要使用純 JDBC 驅動程式,請安裝 MySQL Connector/J。作者下載的是 5.1.x 版的 ZIP Archive,檔案名稱為 mysql-connector-java-5.1.x.zip。將檔案解壓縮之後, 請在解壓縮的目錄內,將 mysql-connector-java-5.1.x-bin.jar 設定到適當的 環境變數 CLASSPATH 內;如果你的開發環境包含 Tomcat,則我們建議 你將 mysql-connector-java-5.1.x-bin.jar 放置於 tomcat\shared\lib 目錄內。假設 Tomcat 安裝於 e:\tomcat,請將該 jar 檔放置於 tomcat\shared\lib 目錄,並設定適當的環境變數 CLASSPATH。 設定環境變數可以由控制台來完成,或者在"命令提示字元"視窗內輸入:
    set CLASSPATH=.;e:\tomcat\shared\lib\mysql-connector-java-5.1.x-bin.jar;%CLASSPATH%
    
  3. 開發 JDBC 程式:一般來說,以 Java 語言(含 JSP 和 servlet)來連結資料庫,大多需要完成以下的步驟:
    1. 利用 Class.forName(驅動程式的名稱); 載入 JDBC 的驅動程式;以 MySQL 的 JDBC 驅動程式的名稱為例,載入的用法為 Class.forName("com.mysql.jdbc.Driver");。每一種驅動程式都有其相對應的名稱,開發人員在使用之前必須先搞清楚。
    2. 利用 Connection conn = DriverManager.getConnection(資料庫的位置, 帳號名 稱, 密碼); 來產生一個 Java 程式和資料庫之間的連線(也就是 Connection 物件 conn)。 DriverManager.getConnection() 內有三個參數,第一個參數說明程式想要 跟哪一個資料庫連線;同樣的,這個參數的值會因為使用的 JDBC 驅動程式不同而 不同,以我們的範例為例,因為我們使用 MySQL 的 JDBC 驅動程式,而且因為 MySQL 的位置在本機(也就是 127.0.0.1),且因為資料庫的名稱為 "eric", 所以第一個參數值必須為 "jdbc:mysql://127.0.0.1/eric"(其中 jdbc:mysql: 是固定不變的,最後 "//IP 位址/資料庫名稱" 會隨著 MySQL 安裝的 IP 位址以及該 MySQL 上的資料庫名稱的不同而改變)。第二個以及 第三個參數分別為連結該資料庫所需要的"帳號名稱"以及"密碼"。
    3. 連線完成之後,我們可以開始執行 SQL 的指令了。執行 SQL 指令的方式是先 借由 conn 來產生一個 Statement 的物件,然後再藉由 Statement 的物件來執行 SQL 指令。產生 Statement 物件的方式 為 Statement aStatement = conn.createStatement();,其中 aStatement 即為 Statement 物件的名稱。
    4. SQL 指令主要執行"增、刪、改、查"四個動作,而這四個動作中只有"查詢" 會回傳一個表格的資料,其他三種都只回傳一個代表執行是否成功的整數。
      1. 如果 SQL 指令執行"增、刪、改",執行的方式為 aStatement.executeUpdate(SQL指令);,該方法回傳總共被改變的資料筆數。以在 Product 新增一筆編號 5 的產 品為例,我們的程式碼即為 aStatement.executeUpdate("insert into Product values(5,'鍵盤',14.5,2)");;由於只有一筆資料被新增,所以執行後,aStatement.executeUpdate() 會回傳 1。
      2. 如果 SQL 指令執行"查詢",執行的方式為 aStatement.executeQuery(SQL指令 );,該方法回傳查詢的結果;由於 SQL 查詢的結果也是一個表格,該表格由 Java 的 ResultSet 物件所代表。以查詢整個 Product 的資料為例,我們的程式碼即為 ResultSet rs = aStatement.executeQuery("select * from Product");
    5. 如果 SQL 指令是查詢,程式大多會進一步處理該查詢結果,也就是 ResultSet 物件。一個 ResultSet 物件包含兩種資料,一種是該回傳表格的 Metadata(由 ResultSetMetaData 物件所代表;該物件包含總共有幾個欄位、欄位的名稱、 欄位的資料型態等資料),另一種是表格的資料。
      1. 我們可以經由 ResultSetMetaData rsmeta = rs.getMetaData(); 來 取得 ResultSetMetaData 物件;然後經由 int cols = rsmeta.getColumnCount(); 來取得回傳表格的總欄位數;在得到總欄位數 cols 之後,我們就可以經由一個 簡單的 for 迴圈,將每一個欄位的名稱以及資料型態,經由 rsmeta.getColumnLabel(i) 以及 rsmeta.getColumnType(i)
      2. 經由 ResultSet 物件 rs 可以取得實際的查詢資料。在預設的情形下,一開始 rs 指向資料的第 0 筆,我們可以經由 rs.next() 來依序取得下一筆的資料, 一旦下一筆資料不存在,rs.next() 會回傳 false。當 rs.next() 指向某一筆資料的 時候,我們可以利用之前 rsmeta 來取得總欄位數,然後利用 rs.getString(i) 將一個一個欄位的資料以字串的方式取出。除了 getString(i) 的方式之外, 我們也可以利用 getDate(i)getTime(i)getDouble(i)getInt(i) 等方法分別取出資料型態為 Date、Time、double、int 的資料。
    6. 最後,但也是很重要的:在程式結束以前,我們必須將相關的資料庫資源釋放 出來。資源釋放的方式是經由呼叫該物件的 close() 方法達成;若釋放 Statement 物件,則與該 Statement 物件相關的 ResultSet 物件也會被釋放。 另外,在程式的最後,我們也必須經由 conn.close(); 將連線釋放。




    由於這個程式跟之前的 NewODBC.java 幾乎一樣,我們只針對不同的地方 (以綠色標示)作說明。

    import java.sql.*;
    
    public class NewJDBC {
      // 設定 JDBC 驅動程式的名稱:com.mysql.jdbc.Driver
      static String classname = "com.mysql.jdbc.Driver";
    
      // 設定 JDBC 的連線資訊,其中 jdbc:mysql:// 是固定不變的
      // 在 // 之後,首先加上 IP 或者主機名稱,在本例中是 127.0.0.1
      // IP 之後,請接上斜線(/)以及資料庫的名稱,在本例中是 eric
      static String jdbcURL = "jdbc:mysql://127.0.0.1/eric";
      static String UID = "jlu";
      static String PWD = "newpasswd";
      static Connection conn = null;
    
      public static void main( String argv[] ) {
        if(argv.length != 1) {
          System.out.println("Usage: java NewJDBC Product");
          System.exit(2);
        }
        String aQuery = "select * from " + argv[0];
        String iSQL = "insert into " + argv[0] + " values(5,'鍵盤',14.5,2)";
        String uSQL = "update " + argv[0] + " set Name='無線鍵盤' where ID=5";
        String dSQL = "delete from " + argv[0] + " where ID=5";
    
        try {
          // 載入 JDBC 驅動程式
          Class.forName(classname).newInstance();
    
          // connect to Database
          conn = DriverManager.getConnection(jdbcURL,UID,PWD);
    
          // Display current content
          System.out.println("Display current content");
          ShowResults(aQuery);
    
          // Insert a new record
          System.out.println("\nInserting a new record .....");
          InsertNew(iSQL);
          ShowResults(aQuery);
    
          // Update record
          System.out.println("\nUpdateing a record .....");
          UpdateNew(uSQL);
          ShowResults(aQuery);
    
          // Delete record
          System.out.println("\nDeleting a record .....");
          DeleteNew(dSQL);
          ShowResults(aQuery);
    
          conn.close();
        } catch (Exception sqle) {
          System.out.println(sqle);
          System.exit(1);
        }
      }
    
      private static void DeleteNew(String dSQL) {
        try {
          Statement aStatement = conn.createStatement();
          aStatement.executeUpdate(dSQL);
        } catch (Exception e) {
          System.out.println("Delete Error: " + e);
          System.exit(1);
        }
      }
    
      private static void UpdateNew(String uSQL) {
        try {
          Statement aStatement = conn.createStatement();
          aStatement.executeUpdate(uSQL);
        } catch (Exception e) {
          System.out.println("Update Error: " + e);
          System.exit(1);
        }
      }
    
      private static void InsertNew(String iSQL) {
        try {
          Statement aStatement = conn.createStatement();
          aStatement.executeUpdate(iSQL);
        } catch (Exception e) {
          System.out.println("Insert Error: " + e);
          System.exit(1);
        }
      }
    
    
      private static void ShowResults(String aQuery) {
        try {
          Statement aStatement = conn.createStatement();
          ResultSet rs = aStatement.executeQuery(aQuery);
    
          ResultSetMetaData rsmeta = rs.getMetaData();
          int cols = rsmeta.getColumnCount();
    
          // Display column headers
          for(int i=1; i<=cols; i++) {
            if(i > 1) System.out.print("\t");
            System.out.print(rsmeta.getColumnLabel(i));
          }
          System.out.print("\n");
    
          // Display query results.
          while(rs.next()) {
            for(int i=1; i<=cols; i++) {
              if (i > 1) System.out.print("\t");
              System.out.print(rs.getString(i)); 
            }
            System.out.print("\n");
          }
    
          // Clean up
          aStatement.close();
        }
        // a better exception handling can be used here.
        catch (Exception e) {
          System.out.println("Exception Occurs.");
        }
      }
    }
    




Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu


沒有留言:

張貼留言