JDBC (Java Database Connectivity) 為 Java 應用與關聯式資料庫提供統一 API。無論底層資料庫為 MySQL、PostgreSQL、Oracle 或 SQL Server,核心步驟高度一致。本文以 MySQL 為例,示範完整的連接、查詢與資源管理流程。
Class.forName("com.mysql.cj.jdbc.Driver")(JDBC 4.0+ 可省略,自動 SPI 發現)DriverManager.getConnection(url, user, pass)conn.createStatement() 或 PreparedStatementexecuteQuery() (SELECT) / executeUpdate() (DML/DDL)ResultSet.next() 迭代 + getXxx() 取值import java.sql.*;
public class DBConnection {
public static void main(String[] args) {
// 1. 連線參數
String driver = "com.mysql.cj.jdbc.Driver"; // MySQL 8.0+ 驅動類別
String url = "jdbc:mysql://localhost:3306/userdb?useSSL=false&serverTimezone=UTC";
String username = "test";
String password = "test";
String sql = "SELECT username, useradd, userage FROM user";
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
// 2. 載入驅動 (JDBC 4.0+ 可省略)
Class.forName(driver);
// 3. 建立連線
conn = DriverManager.getConnection(url, username, password);
// 4. 建立 Statement
stmt = conn.createStatement();
// 5. 執行查詢
rs = stmt.executeQuery(sql);
// 6. 處理結果集
while (rs.next()) {
// 兩種取值方式:索引 (1-based) 或欄位名
System.out.println("username: " + rs.getString(1));
System.out.println("useradd: " + rs.getString("useradd"));
System.out.println("userage: " + rs.getInt("userage"));
System.out.println("-------------------");
}
} catch (ClassNotFoundException e) {
System.err.println("驅動程式未找到:請確認 mysql-connector-java.jar 在 classpath 中");
e.printStackTrace();
} catch (SQLException e) {
System.err.println("資料庫操作異常:" + e.getMessage());
e.printStackTrace();
} finally {
// 7. 逆序關閉資源(每個獨立 try-catch 確保全部釋放)
closeQuietly(rs);
closeQuietly(stmt);
closeQuietly(conn);
}
}
// 輔助方法:靜默關閉
private static void closeQuietly(AutoCloseable resource) {
if (resource != null) {
try { resource.close(); } catch (Exception ignored) {}
}
}
}
jdbc:mysql://host:port/dbname?key1=value1&key2=value2
常用參數:
useSSL=false // 本地開發關閉 SSL
serverTimezone=UTC // 避免時區警告
characterEncoding=UTF-8 // 強制 UTF-8
allowPublicKeyRetrieval=true // MySQL 8.0 公鑰檢索
autoReconnect=true // 自動重連(生產環境建議用連線池而非此選項)
| 特性 | Statement | PreparedStatement |
|---|---|---|
| SQL 注入防護 | ❌ 無 | ✅ 參數化查詢自動轉義 |
| 效能(重複執行) | 每次編譯 | 預編譯一次,多次執行 |
| 批次處理 | 支援 | 支援,效能更佳 |
| 適用場景 | 靜態 SQL、DDL | 含參數的 DML、高頻查詢 |
// PreparedStatement 範例
String sql = "SELECT * FROM user WHERE username = ? AND userage > ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, "admin");
ps.setInt(2, 18);
try (ResultSet rs = ps.executeQuery()) { /* ... */ }
}
自動關閉實作 AutoCloseable 的資源,碼更簡潔安全:
try (Connection conn = DriverManager.getConnection(url, user, pass);
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
while (rs.next()) { /* 處理 */ }
} catch (SQLException e) { /* 處理異常 */ }
// 無需 finally,編譯器自動生成關閉碼
ClassNotFoundException:驅動 JAR 未加入 classpath。Communications link failure:主機/埠錯誤、防火牆、MySQL bind-address 設定。Access denied:帳號密碼錯誤、權限不足、flush privileges 未執行。Zero date value prohibited:MySQL 5.7+ 預設嚴格模式,需 URL 加 zeroDateTimeBehavior=CONVERT_TO_NULL。頻繁開關物理連線極其昂貴。實務上**必須使用連線池**:
// HikariCP 範例
HikariConfig config = new HikariConfig();
config.setJdbcUrl(url);
config.setUsername(user);
config.setPassword(pass);
config.setMaximumPoolSize(20);
DataSource ds = new HikariDataSource(config);
// 使用
try (Connection conn = ds.getConnection()) { /* ... */ }