首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

JDBC 核心技術全棧指南:DriverManager、Statement、PreparedStatement、CallableStatement、連接池與事務

     編輯:Java 相關知識

JDBC 架構分層


應用代碼
    │
    ▼
JDBC API (java.sql / javax.sql)
    │  ┌─ DriverManager / DataSource
    │  ├─ Connection
    │  ├─ Statement / PreparedStatement / CallableStatement
    │  └─ ResultSet
    ▼
JDBC Driver (廠商實現: mysql-connector-j, postgresql, ojdbc, mssql-jdbc)
    │
    ▼
數據庫服務器

核心 API 速查

接口/類核心方法用途
DriverManagergetConnection(url, props)簡單獲取連接(非池化)
DataSourcegetConnection()連接池標準入口
ConnectioncreateStatement()
prepareStatement(sql)
prepareCall(sql)
setAutoCommit(false)
commit()/rollback()
會話控制、事務、創建執行器
StatementexecuteUpdate(sql)
executeQuery(sql)
靜態 SQL
PreparedStatementsetX(index, val)
executeUpdate()
executeQuery()
預編譯、防注入、批量
CallableStatementregisterOutParameter(idx, type)
getX(idx)
存儲過程
ResultSetnext()
getX(colName/index)
getMetaData()
結果集游標

標準 CRUD 模板

1. 查詢


String sql = "SELECT id, name, age FROM users WHERE age > ? AND status = ?";
try (Connection conn = ds.getConnection();
     PreparedStatement ps = conn.prepareStatement(sql)) {
    ps.setInt(1, 18);
    ps.setString(2, "ACTIVE");
    try (ResultSet rs = ps.executeQuery()) {
        while (rs.next()) {
            User u = new User();
            u.setId(rs.getLong("id"));
            u.setName(rs.getString("name"));
            u.setAge(rs.getInt("age"));
            list.add(u);
        }
    }
}

2. 插入/更新/刪除


String sql = "INSERT INTO users(name, age, status) VALUES (?, ?, ?)";
try (Connection conn = ds.getConnection();
     PreparedStatement ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
    ps.setString(1, "Alice");
    ps.setInt(2, 25);
    ps.setString(3, "ACTIVE");
    int affected = ps.executeUpdate();
    if (affected > 0) {
        try (ResultSet keys = ps.getGeneratedKeys()) {
            if (keys.next()) System.out.println("新增 ID: " + keys.getLong(1));
        }
    }
}

3. 批量操作


String sql = "INSERT INTO logs(level, msg) VALUES (?, ?)";
try (Connection conn = ds.getConnection();
     PreparedStatement ps = conn.prepareStatement(sql)) {
    conn.setAutoCommit(false);
    for (LogEntry e : entries) {
        ps.setString(1, e.getLevel());
        ps.setString(2, e.getMsg());
        ps.addBatch();
    }
    int[] counts = ps.executeBatch();
    conn.commit();
}

4. 存儲過程


-- MySQL 示例
CREATE PROCEDURE get_user_count(IN min_age INT, OUT total BIGINT)
BEGIN SELECT COUNT(*) INTO total FROM users WHERE age >= min_age; END;

String sql = "{CALL get_user_count(?, ?)}";
try (Connection conn = ds.getConnection();
     CallableStatement cs = conn.prepareCall(sql)) {
    cs.setInt(1, 18);
    cs.registerOutParameter(2, Types.BIGINT);
    cs.execute();
    System.out.println("用戶數: " + cs.getLong(2));
}

事務管理模式


// 編程式事務
public void transfer(long from, long to, BigDecimal amount) {
    Connection conn = null;
    try {
        conn = ds.getConnection();
        conn.setAutoCommit(false);
        // 扣減
        updateBalance(conn, from, amount.negate());
        // 增加
        updateBalance(conn, to, amount);
        conn.commit();
    } catch (Exception e) {
        if (conn != null) conn.rollback();
        throw new RuntimeException(e);
    } finally {
        if (conn != null) conn.setAutoCommit(true); // 歸還池前恢復
    }
}

生產環境建議使用 @Transactional (Spring) 或程序化 TransactionTemplate。

連接池選型

HikariCP 基礎配置


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: 123456
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
      connection-timeout: 30000
      idle-timeout: 600000
      max-lifetime: 1800000
      connection-test-query: SELECT 1

避坑指南

  • ❌ 長時間持有 Connection → 池耗盡 → 設置 max-lifetime、idle-timeout
  • ❌ Statement 未關閉 → 游標洩漏 → try-with-resources 強制關閉
  • ❌ 拼接 SQL 導致注入 → 全量 PreparedStatement
  • ❌ 大結果集一次性載入 OOM → setFetchSize(100) + 流式處理 / 分頁
  • ❌ 事務邊界不清 → 數據不一致 → 統一用 @Transactional 宣告式

現代替代方案

  • MyBatis / JPA / jOOQ:ORM/映射框架,減少樣板代碼
  • Spring JDBC Template:簡化 JDBC 模板
  • R2DBC:響應式非阻塞驅動

理解 JDBC 底層原理,排查連接洩漏、死鎖、慢 SQL 才能得心應手。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
連接池特點推薦場景
HikariCP極速、輕量、預設配置優秀默認首選 (Spring Boot 2+ 默認)
Druid監控強、SQL 防火墻、阿里出品需要詳細監控、防注入
Tomcat JDBC PoolTomcat 內置、穩定Tomcat 環境無額外依賴