JDBC (Java Database Connectivity) 是 Java 操作關聯式資料庫的標準 API。本文系統梳理:JDBC 本質、核心介面、標準操作流程、Oracle/MySQL 實戰、三版本封裝演進 (工具類 → Properties 配置 → 連線池)、資源管理鐵律與最佳實踐。
| 介面 | 職責 | 關鍵方法 |
| Driver | 驅動註冊與連線建立 | connect(url, props) |
| Connection | 資料庫會話、事務控制 | createStatement、prepareStatement、commit、rollback、setAutoCommit |
| Statement | 靜態 SQL 執行 | executeQuery、executeUpdate、execute |
| PreparedStatement | 預編譯參數化 SQL (防注入) | setXxx、addBatch、executeBatch |
| CallableStatement | 儲存過程/函數呼叫 | registerOutParameter、execute |
| ResultSet | 查詢結果游標 | next、getXxx、close |
標準操作五步驟
// 1. 載入驅動 (JDBC 4.0+ 可省略,SPI 自動發現)
Class.forName("oracle.jdbc.OracleDriver"); // 或 com.mysql.cj.jdbc.Driver
// 2. 建立連線
Connection conn = DriverManager.getConnection(
"jdbc:oracle:thin:@//host:1521/service", "user", "pwd");
// 3. 建立 Statement / PreparedStatement
PreparedStatement ps = conn.prepareStatement(
"INSERT INTO emp(empno, ename, sal, deptno) VALUES (?, ?, ?, ?)");
// 4. 綁定參數、執行
ps.setInt(1, 1001);
ps.setString(2, "Alice");
ps.setDouble(3, 8000);
ps.setInt(4, 10);
int rows = ps.executeUpdate(); // DML 返回影響行數
// 5. 關閉資源 (逆序、分別 try-catch、finally 保證)
ResultSet rs = null;
try { /* ... */ }
finally {
closeQuietly(rs);
closeQuietly(ps);
closeQuietly(conn);
}
三版本封裝演進
V1:硬編碼工具類
public class DBUtilV1 {
private static final String URL = "jdbc:oracle:thin:@localhost:1521:orcl";
private static final String USER = "scott", PWD = "tiger";
static { Class.forName("oracle.jdbc.OracleDriver"); }
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL, USER, PWD);
}
public static void close(Connection c) { /* ... */ }
}
缺點:修改配置需改代碼重編譯。
V2:Properties 外部配置
// db.properties
jdbc.driver=oracle.jdbc.OracleDriver
jdbc.url=jdbc:oracle:thin:@//host:1521/service
jdbc.user=scott
jdbc.password=tiger
// DBUtilV2
static {
Properties p = new Properties();
p.load(DBUtilV2.class.getClassLoader().getResourceAsStream("db.properties"));
URL = p.getProperty("jdbc.url"); // ...
Class.forName(p.getProperty("jdbc.driver"));
}
優點:配置與代碼分離,部署環境只改 properties。
V3:生產級連線池
手寫連線池易出 Bug (併發、洩漏、超時、驗證)、**強烈建議直接使用成熟連線池**:
- HikariCP:極致效能、輕量、Spring Boot 2+ 預設。
- Druid:阿里出品、監控強大、SQL 防火牆。
- DBCP2 / c3p0:老牌,較少新專案採用。
HikariCP 整合範例
// application.yml (Spring Boot)
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/mydb?useSSL=false&serverTimezone=UTC
username: root
password: secret
hikari:
maximum-pool-size: 20
minimum-idle: 5
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
// 使用
@Autowired DataSource dataSource;
try (Connection conn = dataSource.getConnection()) { ... }
資源管理鐵律
- 逆序關閉:ResultSet → Statement → Connection。
- 分別 try-catch:單一 close 拋異常不影響後續關閉。
- Java 7+ try-with-resources:自動關閉實作
AutoCloseable 的資源。
try (Connection conn = ds.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ResultSet rs = ps.executeQuery()) {
while (rs.next()) { /* ... */ }
} // 自動關閉,即使拋異常
防止 SQL 注入:PreparedStatement 鐵律
// 錯誤:字串拼接
String sql = "SELECT * FROM user WHERE name = '" + name + "'"; // 注入風險
// 正確:參數化查詢
String sql = "SELECT * FROM user WHERE name = ?";
ps.setString(1, name); // 驅動負責轉義、型別轉換
批次處理大幅提升寫入效能
conn.setAutoCommit(false);
String sql = "INSERT INTO log(ts, msg) VALUES (?, ?)";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
for (LogEvent e : events) {
ps.setTimestamp(1, new Timestamp(e.getTime()));
ps.setString(2, e.getMsg());
ps.addBatch();
if (++count % 1000 == 0) ps.executeBatch();
}
ps.executeBatch();
conn.commit();
}
總結
JDBC 是持久層基石。理解其介面設計、資源管理、連線池原理,能讓你在排查連線洩漏、調優批次寫入、選擇 ORM 框架時擁有底層視野。現代專案:拒絕手寫連線池,直接上 HikariCP/Druid。
- 上一篇文章: Java ClassName.this 語法深度解析:內部類存取外部類實例的關鍵
- 下一篇文章: Java 實現迷宮小遊戲:深度優先生成與鍵盤交互完整代碼
Copyright ©
程式碼之家 All Rights Reserved