本教學示範如何使用 Servlet 搭配 JDBC-ODBC Bridge 驅動程式,對 Microsoft Access 資料庫執行「查詢顯示、新增、更新」操作。雖然 Access 與 JDBC-ODBC Bridge 已非現代主流選擇,但完整流程展示了 JDBC 核心 API 用法,易於移植至 MySQL/PostgreSQL/Oracle 等生產級資料庫。
odbc_exmp.mdbNames:
ID (AutoNumber, Primary Key)
first_name (Text)
last_name (Text)
odbc_exmp → 選擇資料庫檔案webapps/star/ ├── WEB-INF/ │ ├── classes/ │ │ └── com/stardeveloper/servlets/db/DisplayServlet.class │ └── web.xml
package com.stardeveloper.servlets.db;
import java.sql.*;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class DisplayServlet extends HttpServlet {
// GET:顯示查詢表單
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("查詢人員 ");
out.println("");
out.close();
}
// POST:執行查詢並顯示結果
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setContentType("text/html");
PrintWriter out = res.getWriter();
out.println("查詢結果 ");
out.println("ID\tFirst Name\tLast Name");
long start = System.currentTimeMillis();
Connection con = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 1. 載入驅動
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
// 2. 建立連線
con = DriverManager.getConnection("jdbc:odbc:odbc_exmp");
// 3. 建立 Statement
stmt = con.createStatement();
// 4. 執行查詢
rs = stmt.executeQuery("SELECT * FROM Names");
// 5. 迭代結果
while (rs.next()) {
out.print(rs.getObject(1) + "\t");
out.print(rs.getObject(2) + "\t\t");
out.println(rs.getObject(3));
}
} catch (SQLException e) {
throw new ServletException("無法顯示記錄", e);
} catch (ClassNotFoundException e) {
throw new ServletException("找不到 JDBC 驅動", e);
} finally {
// 6. 關閉資源(逆序)
closeQuietly(rs);
closeQuietly(stmt);
closeQuietly(con);
}
long end = System.currentTimeMillis();
out.println("");
out.println("查詢耗時: " + (end - start) + " ms.
");
out.println("返回");
out.println("");
out.close();
}
// 輔助方法:安全關閉
private void closeQuietly(AutoCloseable resource) {
if (resource != null) {
try { resource.close(); } catch (Exception ignored) {}
}
}
}
Class.forName("driver.class.Name") 觸發驅動類別靜態區塊,向 DriverManager 註冊自己DriverManager.getConnection(url, user, pass),URL 格式視驅動而定(jdbc:subprotocol:subname)con.createStatement()、prepareStatement(sql)、prepareCall(sql)executeQuery(sql) → ResultSet(SELECT)executeUpdate(sql) → int 影響列數(INSERT/UPDATE/DELETE/DDL)execute(sql) → boolean(多結果集)rs.next():游標前移,回傳是否有下一列rs.getXxx(columnIndex/Name):取得欄位值rs.getMetaData():取得欄位資訊finally 區塊,確保釋放
String first = req.getParameter("first_name");
String last = req.getParameter("last_name");
String sql = "INSERT INTO Names (first_name, last_name) VALUES (?, ?)";
try (Connection con = DriverManager.getConnection("jdbc:odbc:odbc_exmp");
PreparedStatement ps = con.prepareStatement(sql)) {
ps.setString(1, first);
ps.setString(2, last);
int rows = ps.executeUpdate();
out.println("新增 " + rows + " 筆記錄成功");
} catch (SQLException e) {
throw new ServletException("新增失敗", e);
}
String id = req.getParameter("id");
String first = req.getParameter("first_name");
String last = req.getParameter("last_name");
String sql = "UPDATE Names SET first_name=?, last_name=? WHERE id=?";
try (Connection con = DriverManager.getConnection("jdbc:odbc:odbc_exmp");
PreparedStatement ps = con.prepareStatement(sql)) {
ps.setString(1, first);
ps.setString(2, last);
ps.setInt(3, Integer.parseInt(id));
int rows = ps.executeUpdate();
out.println(rows > 0 ? "更新成功" : "找不到對應記錄");
} catch (SQLException e) {
throw new ServletException("更新失敗", e);
}
| 實踐 | 說明 |
|---|---|
| 使用 PreparedStatement | 防 SQL 注入、預編譯效能、自動處理引號/日期格式 |
| try-with-resources (Java 7+) | 自動關閉 Connection/Statement/ResultSet,程式碼簡潔安全 |
| 連線池 (DBCP/HikariCP) | 生產環境必須,避免頻繁建立/銷毀連線開銷 |
| 參數化配置 | URL、帳號、密碼放在 context-param、JNDI 或外部配置檔,不寫死在代碼 |
| 異常轉換 | SQLException → ServletException/自訂異常,隱藏實作細節,統一錯誤頁面 |
| 關閉順序 | ResultSet → Statement → Connection(逆序) |
| 類型 | 架構 | 效能 | 範例 |
|---|---|---|---|
| Type 1 | JDBC-ODBC Bridge | 低(雙層轉換) | sun.jdbc.odbc.JdbcOdbcDriver |
| Type 2 | Native API + Java Wrapper | 中 | Oracle OCI Driver |
| Type 3 | Middleware Server | 中 | IDA Server |
| Type 4 | Pure Java 直連 DB | 高(零中介) | MySQL Connector/J, PostgreSQL JDBC, Oracle Thin, SQL Server JDBC |
鐵律:永遠優先選擇 Type 4 驅動,幾乎所有主流資料庫都提供。
https://localhost:8080/star/servlet/com.stardeveloper.servlets.db.DisplayServletServlet + JDBC 是 Java Web 資料存取的基石。掌握六大步驟、PreparedStatement、連線池、資源管理、異常轉換、Type 4 驅動選擇,即可構建高效、安全、可維護的資料存取層。後續可引入 Spring JDBC Template、MyBatis、JPA/Hibernate 等框架進一步提升開發效率與抽象層次。