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 以及其 勘誤表。
- 為了讓 Java 程式(包含 JSP、Java Servlets 等)能夠存取資料庫, 昇陽(Sun) 定義了 JDBC 的介面,而各家的資料庫管理系統可以依據這些介面定義, 開發出其資料庫系統的 JDBC 驅動程式。JDBC 驅動程式又分成四大類,其細節 可以參考 資料處理入門,在本文中,我們只針對 JDBC-ODBC 驅動程式來說明。
- JDBC-ODBC 驅動程式:若要使用 JDBC-ODBC 驅動程式,請安裝
MySQL
Connector/ODBC。作者下載的是 5.1.x 版的 ZIP Archive,檔案名稱為
mysql-connector-odbc-noinstall-5.1.x-win32.zip。將檔案解壓縮之後,
請在解壓縮的目錄內,執行 install.bat 即可。請注意,如果你的開發環境
不是 Windows,那麼你的作業環境必須安裝以下驅動程式之一:unixODBC, Apple iODBC,
或者 iODBC。
安裝 JDBC-ODBC 驅動程式之後,你需要在控制台上設定 ODBC 的資訊,這些
資訊包含連結資料庫的電腦在哪裡(IP 或者主機名稱)、資料庫名稱、帳號/密碼、
以及代表以上資訊的一個名稱,該名稱為 Data Source Name(資料來源名稱;
或簡稱 dsn)。你如果
使用的是非 Windows 的 ODBC 驅動程式,則請依據該程式的設定方式進行。
首先,在 Windows XP 的環境下,請利用控制台 --> 效能及維護 -->
系統管理工具 --> 資料來源 (ODBC),並開啟"資料來源",開啟後畫面如下:
第五、六、七個欄位分別是使用者帳號(User)、密碼(Password)、以及 資料庫名稱(Database);依據之前的設定,我們可以分別填入 jlu、newpasswd、 以及 eric。完成後的畫面如下:
- 程式開發:一般來說,以 Java 語言(含 JSP 和 servlet)來連結
資料庫,大多需要完成以下的步驟:
- 利用 Class.forName(驅動程式的名稱); 載入 JDBC 的驅動程式;以 JDBC-ODBC 驅動程式的名稱為例,載入的用法為 Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");。每一種驅動程式都有其相對應的名稱,開發人員在使用之前必須 先搞清楚。
- 利用 Connection conn = DriverManager.getConnection(資料庫的位置, 帳號名稱, 密碼); 來產生一個 Java 程式和資料庫之間的連線(也就是 Connection 物件 conn)。 DriverManager.getConnection() 內有三個參數,第一個參數說明程式想要 跟哪一個資料庫連線;同樣的,這個參數的值會因為使用的 JDBC 驅動程式不同而 不同,以我們的範例為例,因為我們使用 JDBC-ODBC 驅動程式,而經由 ODBC 產生 資料庫連線必須藉助"資料來源名稱"(DSN);因為我們之前設定了一個名為 csie 的 DSN,所以第一個參數值必須為 "jdbc:odbc:csie"(其中 jdbc:odbc: 是 固定不變的,最後一個會隨著之前設定的 DSN 名稱改變而變動)。第二個以及 第三個參數分別為連結該資料庫所需要的"帳號名稱"以及"密碼"。
- 連線完成之後,我們可以開始執行 SQL 的指令了。執行 SQL 指令的方式是先 借由 conn 來產生一個 Statement 的物件,然後再藉由 Statement 的物件來執行 SQL 指令。產生 Statement 物件的方式 為 Statement aStatement = conn.createStatement();,其中 aStatement 即為 Statement 物件的名稱。
- SQL 指令主要執行"增、刪、改、查"四個動作,而這四個動作中只有"查詢"
會回傳一個表格的資料,其他三種都只回傳一個代表執行是否成功的整數。
- 如果 SQL 指令執行"增、刪、改",執行的方式為 aStatement.executeUpdate(SQL指令);,該方法回傳總共被改變的資料筆數。以在 Product 新增一筆編號 5 的產品為例,我們的程式碼即為 aStatement.executeUpdate("insert into Product values(5,'鍵盤',14.5,2)");;由於只有一筆資料被新增,所以執行後,aStatement.executeUpdate() 會回傳 1。
- 如果 SQL 指令執行"查詢",執行的方式為 aStatement.executeQuery(SQL指令);,該方法回傳查詢的結果;由於 SQL 查詢的結果也是一個表格,該表格由 Java 的 ResultSet 物件所代表。以查詢整個 Product 的資料為例,我們的程式碼即為 ResultSet rs = aStatement.executeQuery("select * from Product");。
- 如果 SQL 指令是查詢,程式大多會進一步處理該查詢結果,也就是 ResultSet
物件。一個 ResultSet 物件包含兩種資料,一種是該回傳表格的 Metadata(由
ResultSetMetaData 物件所代表;該物件包含總共有幾個欄位、欄位的名稱、
欄位的資料型態等資料),另一種是表格的資料。
- 我們可以經由 ResultSetMetaData rsmeta = rs.getMetaData(); 來 取得 ResultSetMetaData 物件;然後經由 int cols = rsmeta.getColumnCount(); 來取得回傳表格的總欄位數;在得到總欄位數 cols 之後,我們就可以經由一個 簡單的 for 迴圈,將每一個欄位的名稱以及資料型態,經由 rsmeta.getColumnLabel(i) 以及 rsmeta.getColumnType(i)。
- 經由 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 的資料。
- 最後,但也是很重要的:在程式結束以前,我們必須將相關的資料庫資源釋放 出來。資源釋放的方式是經由呼叫該物件的 close() 方法達成;若釋放 Statement 物件,則與該 Statement 物件相關的 ResultSet 物件也會被釋放。 另外,在程式的最後,我們也必須經由 conn.close(); 將連線釋放。
import java.sql.*; public class NewODBC { // 試著將以下的設定以 properties 的檔案讀進來 // 設定 ODBC-JDBC 驅動程式的名稱 static String classname = "sun.jdbc.odbc.JdbcOdbcDriver"; // ODBC's DNS 設為 csie,你也可以設成其他名稱 static String jdbcURL = "jdbc:odbc:csie"; static String UID = "jlu"; static String PWD = "newpasswd"; static Connection conn = null; public static void main( String argv[] ) { // 說明這個程式的使用方式為執行:java NewODBC Product if(argv.length != 1) { System.out.println("Usage: java NewODBC Product"); System.exit(2); } // 查詢用的 SQL 字串 String aQuery = "select * from " + argv[0]; // 新增資料的 SQL 字串 String iSQL = "insert into " + argv[0] + " values(5,'鍵盤',14.5,2)"; // 修改資料的 SQL 字串 String uSQL = "update " + argv[0] + " set Name='無線鍵盤' where ID=5"; // 刪除資料的 SQL 字串 String dSQL = "delete from " + argv[0] + " where ID=5"; try { // 載入 JDBC-ODBC 驅動程式 Class.forName(classname); // 連結資料庫(藉由 dns、帳號、密碼) conn = DriverManager.getConnection(jdbcURL,UID,PWD); // 顯示目前表格的內容 System.out.println("Display current content"); ShowResults(aQuery); // 新增資料並顯示目前表格的內容 System.out.println("\nInserting a new record ....."); InsertNew(iSQL); ShowResults(aQuery); // 修改資料並顯示目前表格的內容 System.out.println("\nUpdateing a record ....."); UpdateNew(uSQL); ShowResults(aQuery); // 刪除資料並顯示目前表格的內容 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(); // 新增、修改、刪除都跟查詢一樣,在執行 SQL 字串前,必須先 // 產生 statement 物件。但是跟查詢不一樣的地方在於,真正 // 執行的方法用的是 executeUpdate(),而不是 executeQuery() aStatement.executeUpdate(iSQL); } catch (Exception e) { System.out.println("Insert Error: " + e); System.exit(1); } } private static void ShowResults(String aQuery) { try { // 產生一個 SQL statement 物件並利用之前建立的連線 conn // 送給 MySQL,然後在伺服器端執行該 statement 物件中的字串 Statement aStatement = conn.createStatement(); ResultSet rs = aStatement.executeQuery(aQuery); // 執行 SQL 字串後的結果被置放於一個 ResultSet 的物件 // 依據 SQL 的原理,回傳的結果其實也是一個表格(table) // 因此 ResultSet 的物件包含該表格的 Metadata 以及資料 // 表格的 Medata 可以經由 ResultSet 物件的 getMetaData 的 // 方法取得,而取得的 Metadata 由一個 ResultSetMetaData 物件代表 ResultSetMetaData rsmeta = rs.getMetaData(); // 由 getColumnCount() 可以知道表格共有幾個欄位 int cols = rsmeta.getColumnCount(); // 經由 for 迴圈可以得出每一個欄位的名稱 for(int i=1; i<=cols; i++) { if(i > 1) System.out.print("\t"); // 由 getColumnLabel(i) 可以取得第 i 個欄位名稱 System.out.print(rsmeta.getColumnLabel(i)); } System.out.print("\n"); // 經由 while 迴圈可以將資料一筆一筆取出來 // rs.next() 是查詢是否還有下一筆;若有,為 true;反之,為 false while(rs.next()) { for(int i=1; i<=cols; i++) { if (i > 1) System.out.print("\t"); // rs.getString(i) 取得第 i 欄的資料並以字串的方式回傳 System.out.print(rs.getString(i)); } System.out.print("\n"); } // 將 rs 以及 statement 清掉。這個動作很重要,如果不清除的話, // 在資料量很大的情形下,Java 垃圾處理器來不及處理的話,就會出現異常 aStatement.close(); } // a better exception handling can be used here. catch (Exception e) { System.out.println("Exception Occurs."); } } }
Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu
沒有留言:
張貼留言