JDBC 核心七步驟標準流程
- 加載驅動:
Class.forName("com.mysql.cj.jdbc.Driver")
- 定義 URL:
jdbc:mysql://host:3306/db?params
- 獲取連接:
DriverManager.getConnection(url, user, pwd)
- 創建 Statement:
conn.createStatement() / prepareStatement() / prepareCall()
- 執行 SQL:
executeQuery() / executeUpdate() / execute()
- 處理結果:
ResultSet 遍歷 / 影響行數
- 釋放資源:逆序關閉 ResultSet → Statement → Connection
三大 Statement 類型對比
| 類型 | 用途 | 特點 | 防注入 |
| Statement | 靜態 SQL | 簡單、無預編譯 | 無 |
| PreparedStatement | 參數化 SQL | 預編譯、緩存執行計劃 | ✓ 佔位符 ? |
| CallableStatement | 存儲過程 | 調用 {call proc(?,?)} | ✓ |
PreparedStatement 參數綁定完整指南
String sql = "INSERT INTO users(username, email, age, create_time, status) VALUES (?, ?, ?, ?, ?)";
PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
ps.setString(1, "張三"); // String
ps.setString(2, "zhang@example.com");
ps.setInt(3, 25); // 基本類型
ps.setTimestamp(4, new Timestamp(System.currentTimeMillis())); // 日期時間
ps.setBoolean(5, true); // 布爾
int rows = ps.executeUpdate();
// 獲取自增主鍵
try (ResultSet keys = ps.getGeneratedKeys()) {
if (keys.next()) {
long id = keys.getLong(1);
System.out.println("生成 ID: " + id);
}
}
ResultSet 進階操作
// 滾動/可更新 ResultSet
Statement stmt = conn.createStatement(
ResultSet.TYPE_SCROLL_INSENSITIVE, // 可滾動
ResultSet.CONCUR_UPDATABLE // 可更新
);
ResultSet rs = stmt.executeQuery("SELECT * FROM users");
// 絕對/相對定位
rs.absolute(5); // 第 5 行
rs.relative(-2); // 向前 2 行
rs.first(); rs.last(); rs.beforeFirst(); rs.afterLast();
// 更新數據
rs.absolute(3);
rs.updateString("email", "new@email.com");
rs.updateRow(); // 同步到數據庫
// 插入行
rs.moveToInsertRow();
rs.updateString("username", "newuser");
rs.updateString("email", "new@test.com");
rs.insertRow();
rs.moveToCurrentRow();
事務管理
conn.setAutoCommit(false); // 開啟事務
try {
// 多條 SQL
ps1.executeUpdate();
ps2.executeUpdate();
conn.commit(); // 提交
} catch (SQLException e) {
conn.rollback(); // 回滾
throw e;
} finally {
conn.setAutoCommit(true); // 恢復默認
}
// 保存點
Savepoint sp = conn.setSavepoint();
try { ... } catch (Exception e) { conn.rollback(sp); }
批量操作優化
conn.setAutoCommit(false);
String sql = "INSERT INTO logs(level, message) VALUES (?, ?)";
PreparedStatement ps = conn.prepareStatement(sql);
for (LogEntry entry : entries) {
ps.setString(1, entry.getLevel());
ps.setString(2, entry.getMessage());
ps.addBatch(); // 累積批次
if (count % 1000 == 0) {
ps.executeBatch(); // 執行批次
conn.commit();
}
}
ps.executeBatch(); // 剩餘
conn.commit();
連接池配置最佳實踐 (HikariCP)
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC");
config.setUsername("user");
config.setPassword("pwd");
// 核心池大小 = CPU 核心數 * 2 (IO 密集型)
config.setMaximumPoolSize(Runtime.getRuntime().availableProcessors() * 2);
config.setMinimumIdle(5);
// 超時設置
config.setConnectionTimeout(30000); // 獲取連接超時 30s
config.setIdleTimeout(600000); // 空閒回收 10min
config.setMaxLifetime(1800000); // 最大存活 30min
// 連接驗證
config.setValidationTimeout(5000);
config.setLeakDetectionThreshold(60000); // 洩漏檢測 1min
DataSource ds = new HikariDataSource(config);
Oracle 數據庫連接差異
// 驅動: oracle.jdbc.driver.OracleDriver (ojdbc8.jar)
// URL 格式
jdbc:oracle:thin:@host:1521:sid // SID 模式
jdbc:oracle:thin:@host:1521/service // Service 模式
jdbc:oracle:thin:@(description=(address=(host=host)(protocol=tcp)(port=1521))(connect_data=(service_name=svc))) // TNS
// 分頁查詢 (Oracle 12c+)
SELECT * FROM users ORDER BY id OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY;
// 序列獲取自增 ID
INSERT INTO users(id, name) VALUES (seq_users.nextval, ?)
常見異常與排查
| 異常 | 原因 | 解決 |
| Communications link failure | 網絡/防火牆/數據庫未啟動 | 檢查連通性、端口、bind-address |
| Public Key Retrieval is not allowed | MySQL 8 密碼插件 | URL 添加 allowPublicKeyRetrieval=true |
| Server Timezone value unrecognized | 時區不匹配 | serverTimezone=Asia/Shanghai |
| Connection reset | 連接空閒超時被斷開 | 連接池配置 validationQuery/testOnBorrow |
| Packet for query is too large | SQL/結果集過大 | 調大 max_allowed_packet |
生產環境檢查清單
- [ ] 使用連接池 (HikariCP 首選)
- [ ] 所有查詢使用 PreparedStatement
- [ ] 批量操作使用 addBatch/executeBatch
- [ ] 事務邊界清晰,異常回滾
- [ ] 連接池監控指標配置 (活躍/空閒/等待/洩漏)
- [ ] 慢查詢日誌分析與索引優化
- [ ] 數據庫密碼加密存儲 (配置中心/密碼服務)
JDBC 雖然底層,但掌握其核心模式與優化技巧,是構建高性能數據訪問層的基石。