JDBC (Java Database Connectivity) 是 Java 應用連接關係型資料庫的標準 API。本文詳細說明 JDBC 連接資料庫的標準流程、關鍵代碼、常見異常處理,以及生產環境中推薦的連接池與工具類封裝模式。
| 方法 | 適用場景 | 返回值 |
executeQuery(sql) | DQL 查詢 | ResultSet |
executeUpdate(sql) | DML (INSERT/UPDATE/DELETE) | 影響行數 (int) |
execute(sql) | 任意 SQL,常用於 DDL | boolean (是否有 ResultSet) |
推薦使用 PreparedStatement 防止 SQL 注入:
String sql = "SELECT * FROM users WHERE username = ? AND status = ?";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, "admin");
ps.setInt(2, 1);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
System.out.println(rs.getString("username") + " - " + rs.getInt("id"));
}
}
}
4. 處理結果集
try (ResultSet rs = stmt.executeQuery("SELECT id, name FROM users")) {
while (rs.next()) {
int id = rs.getInt("id"); // 或 rs.getInt(1)
String name = rs.getString("name"); // 或 rs.getString(2)
System.out.println(id + ": " + name);
}
}
ResultSet 常用導航方法:next()、previous()、first()、last()、absolute(row)、beforeFirst()、afterLast()
5. 關閉資源(關鍵)
必須在 finally 區塊或使用 try-with-resources (JDK 7+) 確保資源釋放:
// JDK 7+ 推薦寫法:自動關閉
try (Connection conn = DriverManager.getConnection(url, user, password);
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
// 業務邏輯
} catch (SQLException e) {
e.printStackTrace();
}
// 傳統寫法(JDK 6 或需兼容)
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DriverManager.getConnection(url, user, password);
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
// 處理結果
} catch (SQLException e) {
e.printStackTrace();
} finally {
closeQuietly(rs);
closeQuietly(ps);
closeQuietly(conn);
}
private static void closeQuietly(AutoCloseable closeable) {
if (closeable != null) {
try { closeable.close(); } catch (Exception ignored) {}
}
}
生產環境最佳實踐:連接池與工具類
為什麼需要連接池?
- 頻繁創建/銷毀連接開銷大,影響效能
- 無限制創建連接可能耗盡資料庫連接數
- 連接池提供連接復用、超時管理、洩漏檢測等功能
主流連接池對比
| 連接池 | 特點 | 適用場景 |
| HikariCP | 效能最優、輕量、預設 Spring Boot 2.x | 高併發、生產首選 |
| Druid | 阿里開源、監控強大、SQL 防注入 | 需要詳細監控的企業級應用 |
| DBCP2 | Apache 老牌、穩定 | 傳統項目維護 |
| c3p0 | 老牌、功能全但效能一般 | 老舊項目 |
DBUtil 工具類封裝範例(含屬性檔配置)
config.properties
driverClassName=com.mysql.cj.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
username=root
password=123456
maxActive=20
maxWait=3000
DBUtil.java
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class DBUtil {
private static HikariDataSource dataSource;
static {
try {
Properties props = new Properties();
try (InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("config.properties")) {
props.load(is);
}
HikariConfig config = new HikariConfig();
config.setDriverClassName(props.getProperty("driverClassName"));
config.setJdbcUrl(props.getProperty("jdbcUrl"));
config.setUsername(props.getProperty("username"));
config.setPassword(props.getProperty("password"));
config.setMaximumPoolSize(Integer.parseInt(props.getProperty("maxActive", "20")));
config.setConnectionTimeout(Long.parseLong(props.getProperty("maxWait", "3000")));
dataSource = new HikariDataSource(config);
} catch (Exception e) {
throw new ExceptionInInitializerError("資料庫連接池初始化失敗: " + e.getMessage());
}
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public static void close(AutoCloseable... closeables) {
for (AutoCloseable c : closeables) {
if (c != null) {
try { c.close(); } catch (Exception ignored) {}
}
}
}
}
使用範例
public class UserDao {
public User findById(int id) {
String sql = "SELECT * FROM users WHERE id = ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setInt(1, id);
try (ResultSet rs = ps.executeQuery()) {
if (rs.next()) {
User user = new User();
user.setId(rs.getInt("id"));
user.setName(rs.getString("name"));
return user;
}
}
} catch (SQLException e) {
throw new RuntimeException("查詢失敗", e);
}
return null;
}
}
常見問題排查
| 問題 | 可能原因 | 解決方案 |
| Communications link failure | 網路不通、資料庫未啟動、防火牆攔截 | 檢查主機/端口、啟動資料庫、放行防火牆 |
| Access denied for user | 帳號密碼錯誤、權限不足、主機限制 | 確認憑證、授權 GRANT、允許遠程連接 |
| Connection refused | 資料庫服務未啟動、端口錯誤 | 啟動服務、確認端口配置 |
| No suitable driver | 驅動未加載、URL 格式錯誤 | 加入驅動 JAR、修正 URL |
總結
掌握 JDBC 基礎流程是 Java 後端開發的必備技能。生產環境務必使用成熟連接池(推薦 HikariCP),封裝通用工具類,統一異常處理與資源關閉邏輯,才能構建穩定高效的資料存取層。
- 上一篇文章: Java 獲取系統環境參數的完整指南
- 下一篇文章: Java Swing 實現 Windows 檔案總管樹狀視圖
Copyright ©
程式碼之家 All Rights Reserved