JDBC (Java Database Connectivity) 是 Java 訪問關係型資料庫的標準 API。本文系統梳理六大核心類/介面、標準操作流程、PreparedStatement 防注入機制、ResultSet 遍歷模式與事務控制最佳實務。
| 組件 | 角色 | 核心方法 |
|---|---|---|
| DriverManager | 驅動管理與連接獲取 | registerDriver(), getConnection(url, user, pwd), setLoginTimeout() |
| Connection | 資料庫會話/事務邊界 | createStatement(), prepareStatement(sql), getMetaData(), setAutoCommit(), commit(), rollback() |
| Statement | 靜態 SQL 執行 | executeQuery(sql), executeUpdate(sql) |
| PreparedStatement | 參數化 SQL 執行 (預編譯) | setXxx(index, val), executeQuery(), executeUpdate() |
| ResultSet | 查詢結果集游標 | next(), getXxx(index/name), close() |
| DatabaseMetaData | 資料庫結構元數據 | getTables(), getColumns(), getPrimaryKeys() |
// 1. 載入並註冊驅動 (JDBC 4.0+ SPI 機制可省略 Class.forName)
Class.forName("com.mysql.cj.jdbc.Driver"); // MySQL 8.0+
// 2. 建立連接
Connection conn = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/db?useSSL=false&serverTimezone=UTC",
"user", "pwd");
// 3. 創建 Statement
Statement stmt = conn.createStatement();
// 或 PreparedStatement
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM user WHERE name=? AND age>?");
// 4. 執行 SQL
ResultSet rs = stmt.executeQuery("SELECT id,name,title,price FROM books WHERE name='tom' AND price=40");
// 參數化查詢
pstmt.setString(1, "tom");
pstmt.setInt(2, 18);
ResultSet rs2 = pstmt.executeQuery();
// 5. 處理結果集
while (rs.next()) {
// 兩種獲取方式
String id = rs.getString(1); // 索引 (從 1 開始)
String name = rs.getString("name"); // 列名 (推薦:可讀性強、抗 Schema 變更)
// getInt, getDouble, getDate, getTimestamp...
}
// 6. 關鍵:逆序關閉資源
rs.close();
stmt.close(); // 或 pstmt.close()
conn.close(); // 歸還連接池 (若使用 DataSource)
| 版本 | 機制 | 代碼 |
|---|---|---|
| JDBC 4.0 前 | 手動載入+註冊 | Class.forName(...); DriverManager.registerDriver(...) |
| JDBC 4.0+ (Java 6+) | SPI 自動發現 | 驅動 JAR META-INF/services/java.sql.Driver 列出實現類,無需任何代碼 |
MySQL 驅動特例:com.mysql.jdbc.Driver 靜態塊已自動註冊,僅需 Class.forName 觸發載入即可。
String sql = "SELECT * FROM users WHERE username=? AND password=?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, username); // 索引從 1 開始 pstmt.setString(2, password); // setInt, setLong, setDate, setTimestamp, setNull... ResultSet rs = pstmt.executeQuery();
原理:SQL 模板預編譯,參數作為數據而非代碼傳遞,徹底阻斷注入攻擊。同時提升重複執行效能(執行計劃復用)。
Connection conn = null;
try {
conn = dataSource.getConnection(); // 或 DriverManager.getConnection
conn.setAutoCommit(false); // 關鍵:關閉自動提交
// 業務操作 1
stmt.executeUpdate("UPDATE account SET money=money-1000 WHERE name='zhangsan'");
// 業務操作 2
stmt.executeUpdate("UPDATE account SET money=money+1000 WHERE name='lisi'");
conn.commit(); // 成功提交
} catch (Exception e) {
e.printStackTrace();
if (conn != null) conn.rollback(); // 失敗回滾
} finally {
// 逆序關閉
if (stmt != null) stmt.close();
if (conn != null) conn.close();
}
setAutoCommit(boolean):false 開啟手動事務模式commit():提交事務,持久化所有變更rollback():回滾事務,撤銷所有未提交變更AutoCloseable 的資源conn.close() 實為歸還池中PreparedStatement 物件ResultSet 流式處理:大數據量避免全量載入記憶體,邊讀邊處SQLException 包裝為業務異常,隱藏資料庫細節JDBC 雖是底層 API,但理解其核心機制——連接管理、預編譯防注入、結果集游標、事務邊界——是掌握 MyBatis、JdbcTemplate、Hibernate 等上層框架原理、排查疑難雜癥、進行效能調優的基石。現代開發建議:業務代碼使用 Spring Data/JPA/MyBatis,僅在框架擴展/極致效能場景直接操作 JDBC。