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

JDBC 核心技術全棧指南:從驅動載入到事務控制、批次更新、元數據分析

     編輯:Java 程式設計入門

JDBC (Java Database Connectivity) 是 Java 操作關聯式資料庫的統一 API 標準。掌握其核心介面、標準流程、事務邊界控制、批次處理與元數據編程,是構建高效、安全資料存取層的必修課。

一、 核心 API 體系速覽

介面/類別核心職責關鍵方法
DriverManager驅動管理、獲取連線getConnection(url, user, pwd)
Connection資料庫會話、事務控制、Statement 工廠createStatement(), prepareStatement(), setAutoCommit(), commit(), rollback(), setSavepoint()
Statement執行靜態 SQLexecuteQuery(), executeUpdate(), execute()
PreparedStatement預編譯參數化 SQL (防注入、效能優)setXxx(index, val), executeQuery(), executeUpdate()
CallableStatement呼叫預存程序registerOutParameter(), getXxx()
ResultSet查詢結果集游標next(), getXxx(), updateXxx(), absolute()
ResultSetMetaData結果集結構描述getColumnCount(), getColumnName(), getColumnType()
DatabaseMetaData資料庫產品特性描述supportsBatchUpdates(), getTables(), getColumns()

二、 標準編程六步曲

// 1. 載入驅動 (JDBC 4.0+ SPI 自動載入,可省略)
Class.forName("com.mysql.cj.jdbc.Driver"); 

// 2. 獲取連線
try (Connection conn = DriverManager.getConnection(url, user, pwd)) {
    // 3. 建立 Statement (優先 PreparedStatement)
    try (PreparedStatement ps = conn.prepareStatement(
            "INSERT INTO users(username, email) VALUES (?, ?)")) {
        
        // 4. 綁定參數、執行
        ps.setString(1, "alice");
        ps.setString(2, "alice@example.com");
        int rows = ps.executeUpdate(); // 回傳影響列數
        
        // 5. 處理結果集 (查詢時)
        // try (ResultSet rs = ps.executeQuery()) { while(rs.next()) { ... } }
    }
} // try-with-resources 自動關閉資源、釋放連線回池

三、 三大 Statement 對比與選型

特性StatementPreparedStatementCallableStatement
SQL 編譯每次執行編譯預編譯一次,多次執行預編譯 CALL 語法
參數綁定字串拼接 (風險高)setXxx() 型別安全setXxx() + registerOutParameter()
防 SQL 注入無強 (參數與代碼分離)強
效能低高 (計畫快取)高
適用場景極簡測試、DDL95% 以上業務 SQL預存程序、複雜邏輯下推
鐵律:業務代碼 永遠使用 PreparedStatement,拒絕字串拼接。

四、 ResultSet 進階操作

1. 可捲動、可更新結果集


// 建立支援雙向游標、可更新的 ResultSet
try (Statement stmt = conn.createStatement(
        ResultSet.TYPE_SCROLL_INSENSITIVE,  // 可捲動,不敏感底層變更
        ResultSet.CONCUR_UPDATABLE)) {      // 可更新
    
    try (ResultSet rs = stmt.executeQuery("SELECT id, name FROM users")) {
        rs.last();              // 移至最後一行
        rs.previous();          // 移至上一行
        rs.absolute(5);         // 移至第 5 行
        
        // 更新當前行
        rs.updateString("name", "newName");
        rs.updateRow();         // 同步回資料庫
        
        // 插入新行
        rs.moveToInsertRow();
        rs.updateString("name", "inserted");
        rs.insertRow();
        rs.moveToCurrentRow();
    }
}

2. Blob/CLOB 大物件處理

// 寫入圖片
try (PreparedStatement ps = conn.prepareStatement("INSERT INTO docs(file) VALUES (?)");
     FileInputStream fis = new FileInputStream("logo.png")) {
    ps.setBinaryStream(1, fis, fis.available());
    ps.executeUpdate();
}

// 讀取圖片
try (ResultSet rs = stmt.executeQuery("SELECT file FROM docs WHERE id=1")) {
    if (rs.next()) {
        try (InputStream is = rs.getBinaryStream("file");
             FileOutputStream fos = new FileOutputStream("out.png")) {
            byte[] buf = new byte[4096];
            for (int len; (len = is.read(buf)) > 0; ) fos.write(buf, 0, len);
        }
    }
}

3. ResultSetMetaData 動態獲取結構

ResultSetMetaData meta = rs.getMetaData();
int cols = meta.getColumnCount();
for (int i = 1; i <= cols; i++) {
    System.out.printf("欄位 %d: %s (%s)%n", 
        i, meta.getColumnName(i), meta.getColumnTypeName(i));
}

五、 事務管理:ACID 與 JDBC 控制

1. 事務邊界控制

Connection conn = null;
try {
    conn = dataSource.getConnection();
    conn.setAutoCommit(false); // 開啟事務
    
    // 業務操作 A
    updateBalance(conn, from, -100);
    // 業務操作 B
    updateBalance(conn, to, +100);
    
    conn.commit(); // 全部成功提交
} catch (SQLException e) {
    if (conn != null) conn.rollback(); // 任一失敗回滾
    throw e;
} finally {
    if (conn != null) {
        conn.setAutoCommit(true); // 歸還連線池前恢復預設
        conn.close();
    }
}

2. 保存點:巢狀事務模擬

Savepoint sp1 = conn.setSavepoint("BeforeRiskyOp");
try { riskyOperation(); }
catch (Exception e) { conn.rollback(sp1); } // 僅回滾到保存點
// 繼續其他操作...
conn.releaseSavepoint(sp1);

3. 隔離級別設定

conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
// 可選:READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE

六、 批次更新:大量寫入加速器

public int[] batchInsert(List users) {
    String sql = "INSERT INTO users(name, email) VALUES (?, ?)";
    try (Connection conn = dataSource.getConnection();
         PreparedStatement ps = conn.prepareStatement(sql)) {
        
        conn.setAutoCommit(false); // 單一事務包裹整批
        for (User u : users) {
            ps.setString(1, u.getName());
            ps.setString(2, u.getEmail());
            ps.addBatch();
        }
        
        int[] results = ps.executeBatch(); // 一次性送往資料庫
        conn.commit();
        return results; // 每條 SQL 影響列數陣列
    } catch (BatchUpdateException e) {
        // 部分失敗處理
        int[] ok = e.getUpdateCounts();
        // ...
        throw e;
    }
}
批次更新黃金法則:關閉自動提交 → addBatch() 累積 → executeBatch() → commit() → 異常時 rollback()。

七、 DatabaseMetaData:跨資料庫適配利器

DatabaseMetaData dbMeta = conn.getMetaData();

// 1. 判斷資料庫能力
boolean batch = dbMeta.supportsBatchUpdates();
boolean savepoint = dbMeta.supportsSavepoints();

// 2. 獲取所有表資訊
try (ResultSet tables = dbMeta.getTables(null, "public", "%", new String[]{"TABLE"})) {
    while (tables.next()) {
        System.out.println(tables.getString("TABLE_NAME"));
    }
}

// 3. 獲取特定表欄位結構
try (ResultSet cols = dbMeta.getColumns(null, "public", "users", "%")) {
    while (cols.next()) {
        System.out.printf("%s %s nullable=%s%n",
            cols.getString("COLUMN_NAME"),
            cols.getString("TYPE_NAME"),
            cols.getString("IS_NULLABLE"));
    }
}

八、 實戰最佳實踐清單

  1. 連線池必備:HikariCP / Druid,生產環境禁用 DriverManager 直連。
  2. PreparedStatement 快取:連線池層面開啟 prepStmtCacheSize 避免重複編譯。
  3. 資源自動管理:全面使用 try-with-resources (JDK 7+)。
  4. 大數據分頁:避免 LIMIT offset, size 深分頁,改用游標/Keyset 分頁。
  5. 參數型別匹配:setLong() 對應 BIGINT,避免隱式轉換導致索引失效。
  6. 異常轉換:捕獲 SQLException 包裝為業務異常,保留 SQLState、ErrorCode、原始 SQL 便於排查。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved