資料處理入門
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
請勿轉貼
看其他教材
目錄
- 使用 Properties 來初始化你的程式
- 資料庫
- JDBC 的種類
- 資料庫存取的基本步驟
- 資料庫新增、刪除、查詢、修改
- JDBC 的種類
- 如何從 Unix (或 Linux)連資料庫?
- 從 applet 連資料庫的問題
- 讀取 Excel 的資料
使用 Properties 來初始化你的程式
在 Win32 的系統上,我們經常將會變動的值儲存在設定檔中(.ini) -- 例如安裝路徑,使用者帳號,密碼,JDBC 的 driver 等 --以便 在不同的環境下,只需要變更設定檔而不需重新 compile 每一個程式。 這種設定檔在 Java 的情形,我們稱 Properties 檔。- 擺放初始值的檔案(meta.txt)
dbUser=monkey dbPasswd=password
- 讀取初始值的程式
import java.util.*; import java.io.*; public class LoadProperty { public static void main(String argv[]) { Properties props = new Properties(); try { props.load(new FileInputStream("meta.txt")); } catch (IOException ioe) { System.out.println("Open meta.txt Error!"); System.exit(1); } System.out.println(props.getProperty("dbUser")); System.out.println(props.getProperty("dbPasswd")); } }
// // 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)」 --> 「完成」
- 新增 (insert): 將一筆資料加入 Product.
insert into Product values ('5','燒錄器', 15000, 10)
- 查詢 (select):
- 查詢全部資料:
select * from Product
- 查詢名稱為'燒錄器'的相關資料:
select * from Product where Name='燒錄器'
- 查詢名稱為'燒錄器'的目前存量:
select Name, Qty from Product where Name='燒錄器'
- 查詢單價低於 2500 元的產品:
select * from Product where Price < 2500
- 查詢單價介於 300 與 10000 元間的產品:
select * from Product where Price >= 300 and Price < 10000
- 查詢全部資料:
- 更改 (update): 將燒錄器的存量改為 20.
update Product set Qty=20 where Name='燒錄器'
- 刪除 (delete): 刪除燒錄器的產品資料
delete from Product where Name='燒錄器'
JDBC 的種類
- JDBC-ODBC bridge plus ODBC driver.
- JDBC-ODBC bridge <--> ODBC driver <--> DBMS
- Limitations: slower, requires 3rd party driver on non-Win32 machine, ODBC was written in C (中文化).
- Native-API partly-Java driver.
- JDBC-API <--> DBMS (compare to category 4)
- this type of driver requires that some operating system-specific binary code be loaded on each client machine.
- JDBC-Net pure Java driver.
- JDBC <--> middleware on client <--> middleware on server <--> DBMS
- In general, this is the most flexible JDBC alternative.
- Native-protocol pure Java driver.
- JDBC driver <--> DBMS
- In general, JDBC drivers are provided by DBMS vendors.
資料庫存取的基本步驟
- 載入 JDBC 驅動程式
- 以 jdbc-odbc 為例,Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
- 以 MS SQL 2000 的驅動程式為例,Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
- 以 Oracle 為例,DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
- 連結到資料庫
- 以 jdbc-odbc 為例,Connection conn = DriverManager.getConnection("jdbc:odbc:odbc-DSN"); 注意,建議使用「系統的 DSN」。
- 以 MS SQL 2000 的驅動程式為例,Connection conn = DriverManager.getConnection("jdbc:microsoft:sqlserver://hostname:1433","username","password"); 有了 SQL 2000 的純 JDBC 驅動程式,你可以從非 Windows 平台連結上 SQL 2000。
- 以 Oracle 為例,Connection conn = DriverManager.getConnection ("jdbc:oracle:thin:username/password@hostname:1521:sid");
- 建立並執行 SQL 指令。每一個 Connection 可以執行多個 Statement,而不需要為每一個 Statement 建立一個 Connection。建立 Connection 的成本是蠻高的!
Statement aStatement = conn.createStatement(); ResultSet rs = aStatement.executeQuery(aQuery);
- 處理由資料庫回傳的資料(ResultSet)
- 結束與資料庫的連線。注意,請在 Statement 不再需要的時候就把他 close 掉,同樣的程式結束以前(包含發生例外狀況時的例外處理),一定要記得結束連線。
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 來連結資料庫並不是 一個非常好的方式,我們試著以下列的範例作說明。- 試試看下列的程式
// // Example JDBC Applet // import java.sql.*; import java.awt.*; import javax.swing.*; import java.awt.event.*; public class OdbcJdbc extends JApplet implements ActionListener { private String classname = "sun.jdbc.odbc.JdbcOdbcDriver"; private String jdbcURL = "jdbc:odbc:dbms"; private String UID = "UID"; private String PWD = "PWD"; private Connection conn = null; private JLabel prompt; private JTextField input; private JTextArea outputArea; private String aQuery = "select * from department"; public void init() { // create visual presentation JPanel p = new JPanel(); p.setLayout(new FlowLayout(FlowLayout.LEFT)); prompt = new JLabel("Table Name"); input = new JTextField(aQuery, 20); p.add(prompt); p.add(input); outputArea = new JTextArea( 10, 30 ); Container c = getContentPane(); c.setLayout(new BorderLayout()); c.add("North", p); c.add("Center", new JScrollPane(outputArea)); // register event handler input.addActionListener(this); } public void actionPerformed( ActionEvent ev ) { String text = ev.getActionCommand(); outputArea.setText(""); // Loading JDBC driver try { Class.forName(classname); } catch (Exception e) { outputArea.append("Loading JDBC error!\n"); outputArea.append(e.toString()); outputArea.append("\n"); } try { // connect to Database conn = DriverManager.getConnection(jdbcURL,UID,PWD); } catch (SQLException sqle) { outputArea.append("Connection to database error!\n"); } showResults(text); try { conn.close(); } catch (Exception ex) { outputArea.append("Connection close error.\n"); } } private 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) outputArea.append("\t"); outputArea.append(rsmeta.getColumnLabel(i)); } outputArea.append("\n"); // Display query results. while(rs.next()) { for(int i=1; i<=cols; i++) { if (i > 1) outputArea.append("\t"); outputArea.append(rs.getString(i)); } outputArea.append("\n"); } // Clean up rs.close(); aStatement.close(); } // a better exception handling can be used here. catch (Exception e) { outputArea.append("Query error!!\n"); } } }
- 你應該會得到下列的錯誤訊息,而造成這個錯誤的原因就是之前所說的
Java Applet 的安全機制(即 sandbox),而這是合理的。想要利用 applet
來連結資料庫,你必須
- 如果你把程式中有關 Swing 的元件換成 AWT 的元件,而且使用 JDK 1.1.x 並利用 appletviewer 來看,你應該可以看的到結果。
- 對於所要執行的 applets 事先先經過簽章。(不在本課程範圍)
- 在 applet 內所欲連結的資料庫同時也存在於你所下載 applet 的網站上。
- 除非你使用 multi-tier 的解決方法,這個方法不在 本課程的範圍(除非我們說明了 RMI 或者 CORBA)。
Can't find Database driver class: java.security.AccessControlException: access denied (java.lang.RuntimePermission accessClassInPackage.sun.jdbc.odbc)
在以下的範例中,我們在 web server 上也安裝了資料庫(我們用 Oracle 8i),- 網頁: classes111.zip 為 Oracle 8i 的 thin JDBC pure Java driver.
<applet codebase="." archive="classes111.zip" code="JdbcApplet" width=500 height=200> </applet>
- 程式
// Import the JDBC classes import java.sql.*; // Import the java classes used in applets import java.awt.*; import java.io.*; import java.util.*; import java.awt.event.*; import javax.swing.*; public class JdbcApplet extends JApplet implements ActionListener { // The connect string static final String connect_string = "jdbc:oracle:thin:@hostname:1521:ora"; // The query we will execute static final String query = "select * from dept"; // The button to push for executing the query JButton execute_button; // The place where to dump the query result JTextArea output; // The connection to the database Connection conn; // Create the User Interface public void init () { Container c = getContentPane(); c.setLayout (new BorderLayout ()); execute_button = new JButton ("Hello JDBC"); c.add ("North", execute_button); output = new JTextArea (10, 60); c.add ("Center", new JScrollPane(output)); execute_button.addActionListener(this); } // Do the work public void actionPerformed (ActionEvent ev) { try { // See if we need to open the connection to the database if (conn == null) { // Load the JDBC driver DriverManager.registerDriver (new oracle.jdbc.driver.OracleDriver()); // Connect to the databse output.append("Connecting to " + connect_string + "\n"); conn = DriverManager.getConnection(connect_string, "UID", "PWD"); output.append ("Connected\n"); } // Create a statement Statement stmt = conn.createStatement (); // Execute the query output.append ("Executing query " + query + "\n"); ResultSet rset = stmt.executeQuery (query); // Dump the result while (rset.next ()) { output.append (rset.getString (1) + "\t"); output.append (rset.getString (2) + "\t"); output.append (rset.getString (3) + "\n"); } // We're done output.append ("done.\n"); } catch (Exception e) { // Oops output.append (e.getMessage () + "\n"); } } }
- 試試看
讀取 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."); } } }
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()); } } }
Written by: 國立中興大學資管系呂瑞麟 Eric Jui-Lin Lu
沒有留言:
張貼留言