首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> MySQL 資料庫 >> MySQL 綜合教學

JDBC 連線 MySQL 完整實戰:從驅動載入到連線池最佳實踐

     編輯:MySQL 綜合教學

JDBC 連線 MySQL 完整實戰:從驅動載入到連線池最佳實踐

JDBC (Java Database Connectivity) 是 Java 應用存取關聯式資料庫的標準 API。本文涵蓋驅動版本選擇、連線參數優化、資源管理模式、預處理防注入、以及生產環境必備的連線池整合。

Maven 依賴(MySQL 8.0+ 驅動)

<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>  <!-- 8.0+ 套件名變更 -->
    <version>8.3.0</version>
</dependency>

<!-- 5.7 專案請用舊驅動 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
</dependency>

基礎連線範例(JDBC 4.0+ 自動載入驅動,無需 Class.forName)

import java.sql.*;

public class JdbcDemo {
    public static void main(String[] args) {
        // 連線 URL 參數詳解見下表
        String url = "jdbc:mysql://127.0.0.1:3306/mydb?" +
                     "useUnicode=true&characterEncoding=utf8mb4&" +
                     "useSSL=false&serverTimezone=Asia/Taipei&" +
                     "allowPublicKeyRetrieval=true&" +
                     "rewriteBatchedStatements=true";  // 批次優化關鍵
        
        String user = "app_user";
        String password = "strongpass";

        // try-with-resources 自動關閉連線/Statement/ResultSet (JDK 7+)
        try (Connection conn = DriverManager.getConnection(url, user, password);
             PreparedStatement ps = conn.prepareStatement(
                 "SELECT id, name, email FROM user WHERE status = ? AND created_at > ?");
             ) {
            
            ps.setInt(1, 1);                    // 防 SQL 注入
            ps.setTimestamp(2, Timestamp.valueOf("2024-01-01 00:00:00"));
            
            try (ResultSet rs = ps.executeQuery()) {
                while (rs.next()) {
                    // 依欄位名取值(推薦),不依索引,避免 SELECT * 順序變更出錯
                    System.out.printf("ID: %d, Name: %s, Email: %s%n",
                        rs.getInt("id"), rs.getString("name"), rs.getString("email"));
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
            // 實際專案應拋出自訂異常、記錄錯誤碼 SQLState
        }
    }
}

關鍵連線 URL 參數對照表

參數推薦值說明
useUnicodetrue使用 Unicode 字元集
characterEncodingutf8mb4支援 Emoji,MySQL 端 CHARSET=utf8mb4 對應
useSSLfalse內網環境關閉 SSL 降低握手延遲;外網必開 true
serverTimezoneAsia/Taipei避免時區不一致導致時間偏移(8.0+ 必填)
allowPublicKeyRetrievaltrue配合 caching_sha2_password 認證插件(8.0 預設)
rewriteBatchedStatementstrue批次 INSERT/UPDATE 重寫為多值語句,效能提升 10~100 倍
useServerPrepStmtstrue啟用伺服器端預處理,減少解析開銷
cachePrepStmtstrue客戶端快取 PreparedStatement
prepStmtCacheSize250快取大小
prepStmtCacheSqlLimit2048快取 SQL 長度上限
connectTimeout10000建立連線超時 ms
socketTimeout30000讀寫超時 ms,防止網路異常卡死
tcpKeepAlivetrue啟用 TCP KeepAlive 偵測死連線

批次操作最佳實踐

// 批次插入 10,000 筆
String sql = "INSERT INTO user (name, email, status) VALUES (?, ?, ?)";
try (Connection conn = dataSource.getConnection();
     PreparedStatement ps = conn.prepareStatement(sql)) {
    
    conn.setAutoCommit(false);  // 手動提交
    int batchSize = 1000;
    
    for (int i = 0; i < 10000; i++) {
        ps.setString(1, "User" + i);
        ps.setString(2, "user" + i + "@example.com");
        ps.setInt(3, 1);
        ps.addBatch();
        
        if (i % batchSize == 0) {
            ps.executeBatch();  // 執行批次
            conn.commit();      // 提交事務
        }
    }
    ps.executeBatch();  // 剩餘
    conn.commit();
} catch (BatchUpdateException e) {
    // 處理部分失敗:e.getUpdateCounts() 取得各條結果
}

生產環境:HikariCP 連線池整合

// Spring Boot application.yml
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/mydb?useUnicode=true&characterEncoding=utf8mb4&useSSL=false&serverTimezone=Asia/Taipei&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true
    username: app_user
    password: ${DB_PASSWORD}
    hikari:
      maximum-pool-size: 20           # CPU核心數×2+1
      minimum-idle: 20                # 固定大小
      idle-timeout: 60000             # 60s < wait_timeout
      max-lifetime: 1800000           # 30min
      connection-timeout: 30000       # 30s
      validation-timeout: 5000
      leak-detection-threshold: 60000 # 洩漏偵測 60s
      pool-name: MyApp-HikariCP
      data-source-properties:
        cachePrepStmts: true
        prepStmtCacheSize: 250
        prepStmtCacheSqlLimit: 2048
        useServerPrepStmts: true

常見坑與解決

現象原因解決
Communications link failure連線池拿到 MySQL 已斷開的閒置連線縮短 idleTimeout;開啟 testWhileIdle / validationQuery
Public Key Retrieval is not allowed8.0 預設 caching_sha2_password 需傳遞公鑰URL 加 allowPublicKeyRetrieval=true 或改用 mysql_native_password
批次 INSERT 極慢未開啟 rewriteBatchedStatementsURL 加 rewriteBatchedStatements=true
時區錯誤 8 小時JVM/MySQL 時區不一致URL 明確指定 serverTimezone=Asia/Taipei
Emoji 存成 ????字元集非 utf8mb4URL characterEncoding=utf8mb4、表 CHARSET=utf8mb4、連線池 connectionInitSql=SET NAMES utf8mb4

資源管理鐵律

  1. 永遠使用 try-with-resources 自動關閉 Connection、Statement、ResultSet,順序相反。
  2. 絕不在循環中建立連線,必須從連線池獲取。
  3. PreparedStatement 防注入,嚴禁字串拼接 SQL。
  4. 大結果集分頁 使用 LIMIT offset, size 或游標 FETCH FIRST n ROWS ONLY,避免一次拉取 OOM。
  5. 事務邊界清晰:conn.setAutoCommit(false) → 業務邏輯 → commit()/rollback() → setAutoCommit(true)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved