資料處理入門

Many examples in this document are adapted from Java: How To Program (3rd Ed.), written by Deitel and Deitel, and Thinking in Java (2nd Edition), written by Bruce Eckel. All examples are solely used for educational purposes. Hopefully, I am not violating any copyright issue here. If so, please do email me.

Please install JDK 1.3.1_02 or later with Java Plugin to view this page. Also, this page is best viewed with browsers (for examples, Mozilla 0.99 or later, IE 6.x or later) with CSS2 support. This document is provided as is. You are welcomed to use it for non-commercial purpose.
Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu

請勿轉貼

看其他教材


目錄

  1. 使用 Properties 來初始化你的程式
  2. 資料庫
  3. JDBC 的種類
  4. 資料庫存取的基本步驟
  5. 資料庫新增、刪除、查詢、修改
  6. JDBC 的種類
  7. 如何從 Unix (或 Linux)連資料庫?
  8. 從 applet 連資料庫的問題
  9. 讀取 Excel 的資料

使用 Properties 來初始化你的程式

在 Win32 的系統上,我們經常將會變動的值儲存在設定檔中(.ini) -- 例如安裝路徑,使用者帳號,密碼,JDBC 的 driver 等 --以便 在不同的環境下,只需要變更設定檔而不需重新 compile 每一個程式。 這種設定檔在 Java 的情形,我們稱 Properties 檔。 另外,System 類別也提供了一系列的 properties 讓開發者來 使用,例如,java.class.path 這個 property 能讓開發人員來 讀取目前系統的 CLASSPATH 的設定,或者 os.version 能讓 開發人員讀取目前使用的作業系統版本。所有系統預設的 properties 可以從 Sun's Accessing System Resource 查到。
//
// to run this program, please enter the following command
// java -DSchool=<some value> TestSystem
//

public class TestSystem {
  public static void main(String[] args) {
    // print out the default system properties
    System.out.println("CLASSPATH = " +
                       System.getProperty("java.class.path"));
    System.out.println("OS Version = " + System.getProperty("os.version"));

    // check to see if user enter property "School"
    // if none is found, the default value "x" is set
    if (System.getProperty("School", "x").equals("x"))
      System.out.println("Usage: java -DSchool=<some value> TestSystem");
    else
      System.out.println("You are a student of " +
                         System.getProperty("School"));
  }
}

資料庫

Java 提供與各種資料庫的連結方式,而聯結資料庫需要驅動程式,這一類給 Java 使用來連結資料庫的程式統稱為 JDBC 驅動程式。JDBC 驅動程式共分成 四個 level 並將於下一個主題討論。在一開始, 我們僅討論如何利用 JDBC-ODBC 的驅動程式與資料庫連結。 (JDBC-ODBC 僅適用於 Win32 的系統) 若你使用 JDK 1.1.x 或以上版本, JDBC-ODBC 的驅動程式已經包含在 JDK 中。 若你尚在使用 JDK 1.0.x, 我建議你升級。 至於最新的 JDBC 驅動程式的 發展, 使用者歡迎到 JDBC Homepage 去找尋資料。 在以下的範例中, 我們使用的是一個 Microsoft Access 的資料庫 -- samples.mdb。 這個資料庫中包含一個 Table, 其名稱為 Product。 Product 有四個欄位 (ID, Name, Price, Qty)。 請於下載後, 利用 ODBC 將其設定為 Samples. 其過程為:
「開始」 --> 「設定」 --> 「控制台」 -->  「ODBC」 -->
「系統資料來源名稱」 -->  「新增」 -->
「Microsoft Access Driver (*.mdb)」  --> 「完成」
在 "資料來源名稱" 欄, 輸入 Samples, 並 「選擇」 samples.mdb 後按 OK。

幾個簡單的 SQL 範例:

  1. 新增 (insert): 將一筆資料加入 Product.
        insert into Product values ('5','燒錄器', 15000, 10)
        
  2. 查詢 (select):
    1. 查詢全部資料:
            select * from Product
            
    2. 查詢名稱為'燒錄器'的相關資料:
            select * from Product where Name='燒錄器'
            
    3. 查詢名稱為'燒錄器'的目前存量:
            select Name, Qty from Product where Name='燒錄器'
            
    4. 查詢單價低於 2500 元的產品:
            select * from Product where Price < 2500
            
    5. 查詢單價介於 300 與 10000 元間的產品:
            select * from Product where Price >= 300 and Price < 10000
            
  3. 更改 (update): 將燒錄器的存量改為 20.
        update Product set Qty=20 where Name='燒錄器'
        
  4. 刪除 (delete): 刪除燒錄器的產品資料
        delete from Product where Name='燒錄器'
        

JDBC 的種類

  1. JDBC-ODBC bridge plus ODBC driver.
  2. Native-API partly-Java driver.
  3. JDBC-Net pure Java driver.
  4. Native-protocol pure Java driver.

資料庫存取的基本步驟

  1. 載入 JDBC 驅動程式
  2. 連結到資料庫
  3. 建立並執行 SQL 指令。每一個 Connection 可以執行多個 Statement,而不需要為每一個 Statement 建立一個 Connection。建立 Connection 的成本是蠻高的!
      Statement aStatement = conn.createStatement();
      ResultSet rs = aStatement.executeQuery(aQuery);
      
  4. 處理由資料庫回傳的資料(ResultSet)
  5. 結束與資料庫的連線。注意,請在 Statement 不再需要的時候就把他 close 掉,同樣的程式結束以前(包含發生例外狀況時的例外處理),一定要記得結束連線。
[註: 使用 JDK 1.1.x,本程式無法顯示中文資料,請使用 JDK 1.3.0_01 以上的版本] 若需顯示中文資料, 請參考 JDBC driver 中文轉碼類別。 此類別為 SQL.java. 使用前述之類別後新的程式碼
import java.sql.*;

public class OldJavaDB 
{
  public static void main( String argv[] )
  {
    // initialize query string
    String aQuery = "select * from Product";

    try
    {
      // load the JDBC-ODBC bridge driver
      Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");

      // connect to Database
      Connection conn = DriverManager.getConnection("jdbc:odbc:Samples");
  
      // Construct a SQL statement and submit it
      Statement aStatement = conn.createStatement();
      ResultSet rs = aStatement.executeQuery(aQuery);

      // Get info about the query results
      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
      rs.close();
      aStatement.close();
      conn.close();
    }
    // a better exception handling can be used here.
    catch (Exception e)
    {
      System.out.println("Exception Occurs.");
    }
  }
}

資料庫新增、刪除、查詢、修改

import java.sql.*;

public class NewJDBC
{
  // 試著將以下的設定以 properties 的檔案讀進來
  static String classname = "sun.jdbc.odbc.JdbcOdbcDriver";
  static String jdbcURL = "jdbc:odbc:dbms";
  static String UID = "uid";
  static String PWD = "pwd";
  static Connection conn = null;

  public static void main( String argv[] )
  {
    // initialize query string
    if(argv.length != 1)
    {
      System.out.println("Usage: java NewJDBC ");
      System.out.println("   ex. java NewJDBC department");
      System.exit(2);
    }
    String aQuery = "select * from " + argv[0];
    String iSQL = "insert into " + argv[0] + " values('資訊管理',3,'456789111','12/30/2000')";
    String uSQL = "update " + argv[0] + " set dname='資訊工程' where dnumber=3";
    String dSQL = "delete " + argv[0] + " where dnumber=3";

    try
    {
      // load the JDBC-ODBC bridge driver
      Class.forName(classname);

      // 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
    {
      // Construct a SQL statement and submit it
      Statement aStatement = conn.createStatement();
      ResultSet rs = aStatement.executeQuery(aQuery);

      // Get info about the query results
      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
      rs.close();
      aStatement.close();
    }
    // a better exception handling can be used here.
    catch (Exception e)
    {
      System.out.println("Exception Occurs.");
    }
  }
}

如何從 Unix (或 Linux)連資料庫?

解釋 Openlink 後,demo 如何在 Linux 上與 Microsoft SQL Server 連結並取得資料。
import java.sql.*;

public class OPLTest 
{
  public static void main( String argv[] )
  {
    // initialize query string
    String aQuery = null;
    Connection conn = null;
    int flag = 0;

    try
    {
      // load the JDBC-ODBC bridge driver
      Class.forName("openlink.jdbc2.Driver");

      if (argv.length == 0)
      {
        System.out.println("Usage: java OPLTest o1 [o2]");
        System.out.println("   o1: pubs, dbms, or bob");
        System.out.println("   o2: odbc or empty");
        System.exit(1);
      }

      // connect to Database
      if (argv[0].equals("bob"))
      {
        // to MS Access via odbc
        flag++;
        aQuery = "select * from books";
        conn = DriverManager.getConnection("jdbc:openlink://163.17.3.151/DSN=bob/");
      }

      if (argv[0].equals("pubs"))
      {
        flag++;
        aQuery = "select * from stores";
        if (argv.length ==2 && argv[1].equals("odbc"))
          // either way is fine.
          conn = DriverManager.getConnection(
                 //"jdbc:openlink://163.17.28.223/DSN=pubs", "uid", "pwd");
                 "jdbc:openlink://163.17.28.223/DSN=pubs/UID=uid/PWD=pwd/");
                 // jdbc:openlink://ODBC is type 1 driver which requires
                 // opljodbc2.jar
                 //"jdbc:openlink://ODBC/DSN=pubs/UID=uid/PWD=pwd/");
                 // jdbc:openlink://UDBC is type 2 driver which requires
                 // opljudbc2.jar
                 //"jdbc:openlink://UDBC/DSN=pubs/UID=uid/PWD=pwd/");
        else
          // DSN-less connection
          conn = DriverManager.getConnection("jdbc:openlink://163.17.28.223:5000/SVT=SQLServer 7/DATABASE=pubs/UID=uid/PWD=pwd/FBS=55/Readonly=Y/");
      }

      if (argv[0].equals("dbms"))
      {
        flag++;
        aQuery = "select * from employee";
        if (argv.length ==2 && argv[1].equals("odbc"))
          conn = DriverManager.getConnection(
                 "jdbc:openlink://163.17.11.7/DSN=dbms","uid","pwd");
        else
          conn = DriverManager.getConnection(
                 "jdbc:openlink://163.17.11.7:5000/Database=dbms/UID=uid/PWD=pwd/SVT=SQLServer 7/FBS=60/Readonly=Y");
      }

      if (flag == 0)
      {
        System.out.println("You define wrong DSN. Only pub, dbms, or bob is allowed.");
        System.exit(2);
      }
  
      // Construct a SQL statement and submit it
      Statement aStatement = conn.createStatement();
      ResultSet rs = aStatement.executeQuery(aQuery);

      // Get info about the query results
      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
      rs.close();
      aStatement.close();
      conn.close();
    }
    // a better exception handling can be used here.
    catch (Exception e)
    {
      System.out.println("Exception Occurs: " + e);
    }
  }
}

從 applet 連資料庫的問題

一般來說,以 Java 的安全機制來看,利用 applet 來連結資料庫並不是 一個非常好的方式,我們試著以下列的範例作說明。

讀取 Excel 的資料

由於 JDBC-ODBC 是經由 ODBC 來讀取資料,因此只要你設定好一個 Excel 檔而且將其指定給一個 ODBC 的 DSN,那麼 Java 也可以 讀取 Excel 的資料。微軟的 ODBC 驅動程式將 spreadsheet 的第一列 當作資料庫的欄位名稱,而將工作表(worksheet)的名稱當作 資料表(table)的名稱。[註:如果你執行下列的程式卻發現在資料 的最後出現許多的 null 值,請將那些列都在 Excel 反白,並執行 「編輯」--> 「刪除」。]
import java.sql.*;

public class JdbcExcel
{
  static String classname = "sun.jdbc.odbc.JdbcOdbcDriver";
  static String jdbcURL = "jdbc:odbc:grades";
  static String UID = "";
  static String PWD = "";
  static Connection conn = null;

  public static void main( String argv[] )
  {
    // initialize query string
    if(argv.length != 1)
    {
      System.out.println("Usage: java JdbcExcel ");
      System.out.println("   ex. java JdbcExcel A");
      System.exit(2);
    }
    String aQuery = "select * from [" + argv[0] + "$]";

    try
    {
      // load the JDBC-ODBC bridge driver
      Class.forName(classname);

      // connect to Database
      conn = DriverManager.getConnection(jdbcURL,UID,PWD);

      // Display current content
      System.out.println("Display current content");
      ShowResults(aQuery);

      conn.close();
    } catch (Exception sqle)
    {
      System.out.println(sqle);
      System.exit(1);
    }
  }

  private static void ShowResults(String aQuery)
  {
    try
    {
      // Construct a SQL statement and submit it
      Statement aStatement = conn.createStatement();
      ResultSet rs = aStatement.executeQuery(aQuery);

      // Get info about the query results
      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
      rs.close();
      aStatement.close();
    }
    // a better exception handling can be used here.
    catch (Exception e)
    {
      System.out.println("Exception Occurs.");
    }
  }
}
可是如果你是在一個非 Windows 的環境下而想能夠從你的 Java 程式存取 Excel 檔的資料,那要怎麼辦呢?這時候你就需要藉助 Jarkata 的 POI, 首先你需要下載 Jarkata POI library,並將 poi.jar 設定在你的 CLASSPATH 的環境變數。假設我們的 Excel 檔的資料是一個成績檔,那麼處理的程式 就如以下範例所示。另外,你也可以參考 Elango Sundaram, Excelling in Excel with Java: Learn how to use the Jakarta POI, JavaWorld, 03/2004.
import java.io.*;
import java.text.*;
import org.apache.poi.poifs.filesystem.*;
import org.apache.poi.hssf.usermodel.*;

public class TestExcel {
  public static void main(String[] args) {
    DecimalFormat f = new DecimalFormat("###");
    try {
      POIFSFileSystem fs      =
               new POIFSFileSystem(new FileInputStream("ds93f.xls"));
      HSSFWorkbook wb = new HSSFWorkbook(fs);
      HSSFSheet sheet = wb.getSheetAt(0);
      HSSFRow row;
      int i = 0;
      short col = (short) (sheet.getRow(0).getLastCellNum() - 1);
      while((row = sheet.getRow(i)) != null) {
        HSSFCell cell;

        if(i != 0 && 
           row.getCell((short)0).getCellType() == HSSFCell.CELL_TYPE_BLANK)
          break;

        for(short j = 2; j < col; j++) {
          cell = row.getCell(j);
          int status = cell.getCellType();
          switch (status) {
            case HSSFCell.CELL_TYPE_STRING:
              System.out.print(cell.getStringCellValue() + "\t");
              break;
            case HSSFCell.CELL_TYPE_NUMERIC:
              System.out.print(f.format(cell.getNumericCellValue()) + "\t");
              break;
            case HSSFCell.CELL_TYPE_FORMULA:
              System.out.print(f.format(cell.getNumericCellValue()) + "\t");
              break;            
            case HSSFCell.CELL_TYPE_BLANK:
              System.out.print("\t");
              break;            
            default:
              System.out.print("unknown type \t");
          }
        }
        System.out.println("");
        i++;
      }
    } catch (IOException e) {
      System.out.println(e.getMessage());
    }
  }
}


Last Updated: Tuesday, 30-Nov-2010 18:17:44 CST
Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu