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

MyEclipse 連接 MySQL 實戰(二):JDBC 核心 API、CRUD 操作與連接池最佳實踐

     編輯:Java 綜合教學

MyEclipse 連接 MySQL 實戰(二):JDBC 核心 API、CRUD 操作與連接池最佳實踐

承接上篇環境配置,本文通過完整代碼示例講解 JDBC 核心六步法、Statement/PreparedStatement 操作、結果集處理、資源關閉模式、SQL 注入防範與連接池引入,幫助你從「能跑通」進階到「生產可用」。

一、JDBC 核心六步法

// 1. 加載驅動(JDBC 4.0+ SPI 機制可省略,但建議保留兼容性)
Class.forName("com.mysql.cj.jdbc.Driver"); // MySQL 8.0+ 驅動類

// 2. 建立連接
String url = "jdbc:mysql://localhost:3306/your_db?useSSL=false&serverTimezone=UTC&characterEncoding=utf8";
String user = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, user, password);

// 3. 創建語句對象
Statement stmt = conn.createStatement();
// 或 PreparedStatement pstmt = conn.prepareStatement(sql);

// 4. 執行 SQL
// 查詢:ResultSet rs = stmt.executeQuery("SELECT * FROM person");
// 增刷改:int rows = stmt.executeUpdate("INSERT INTO person VALUES (3, 'Li', 98)");

// 5. 處理結果集
while (rs.next()) {
    int id = rs.getInt("number");
    String name = rs.getString("name");
    String score = rs.getString("mathsorce");
    System.out.println(id + " " + name + " " + score);
}

// 6. 釋放資源(逆序關閉,finally 塊保證)
rs.close();
stmt.close();
conn.close();

二、完整 CRUD 示例

package jdbc.demo;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class JdbcCrudDemo {
    // 數據庫配置常量
    private static final String URL = "jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC";
    private static final String USER = "root";
    private static final String PASS = "123456";

    public static void main(String[] args) {
        // 1. 插入數據
        insertUsers();

        // 2. 查詢所有
        List users = queryAll();
        users.forEach(System.out::println);

        // 3. 更新
        updateUser(3, "LiMing", 100);

        // 4. 刪除
        deleteUser(4);

        // 5. 再次查詢驗證
        queryAll().forEach(System.out::println);
    }

    // 獲取連接(生產環境應替換為連接池)
    private static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(URL, USER, PASS);
    }

    // 插入多條(批處理優化)
    private static void insertUsers() {
        String sql = "INSERT INTO person (number, name, mathsorce) VALUES (?, ?, ?)";
        try (Connection conn = getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {

            conn.setAutoCommit(false); // 開啟事務
            Object[][] data = {
                {5, "WangWu", 85}, {6, "ZhaoLiu", 92}, {7, "SunQi", 78}
            };
            for (Object[] row : data) {
                pstmt.setInt(1, (Integer) row[0]);
                pstmt.setString(2, (String) row[1]);
                pstmt.setInt(3, (Integer) row[2]);
                pstmt.addBatch();
            }
            pstmt.executeBatch();
            conn.commit();
            System.out.println("批量插入完成");
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    // 查詢所有
    private static List queryAll() {
        List list = new ArrayList<>();
        String sql = "SELECT number, name, mathsorce FROM person";
        try (Connection conn = getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql);
             ResultSet rs = pstmt.executeQuery()) {

            while (rs.next()) {
                User u = new User();
                u.setNumber(rs.getInt("number"));
                u.setName(rs.getString("name"));
                u.setScore(rs.getInt("mathsorce"));
                list.add(u);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return list;
    }

    // 更新
    private static void updateUser(int id, String name, int score) {
        String sql = "UPDATE person SET name=?, mathsorce=? WHERE number=?";
        try (Connection conn = getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setString(1, name);
            pstmt.setInt(2, score);
            pstmt.setInt(3, id);
            int rows = pstmt.executeUpdate();
            System.out.println("更新行數:" + rows);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    // 刪除
    private static void deleteUser(int id) {
        String sql = "DELETE FROM person WHERE number=?";
        try (Connection conn = getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
            pstmt.setInt(1, id);
            int rows = pstmt.executeUpdate();
            System.out.println("刪除行數:" + rows);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

// 實體類
class User {
    private int number;
    private String name;
    private int score;
    // getter/setter/toString...
}

三、關鍵最佳實踐

1. 必須使用 PreparedStatement

  • 防 SQL 注入:參數化查詢,數據與代碼分離
  • 性能優化:SQL 預編譯,重複執行復用執行計劃
  • 類型安全:setInt/setString/setTimestamp 自動處理轉換

2. 資源管理:try-with-resources (JDK 7+)

try (Connection conn = getConnection();
     PreparedStatement pstmt = conn.prepareStatement(sql);
     ResultSet rs = pstmt.executeQuery()) {
    // 業務邏輯
} // 自動關閉 rs → pstmt → conn,即使拋異常

3. 事務控制

conn.setAutoCommit(false);
try {
    // 多條 SQL
    conn.commit();
} catch (SQLException e) {
    conn.rollback();
    throw e;
} finally {
    conn.setAutoCommit(true); // 恢復默認
}

4. 結果集類型與並發性

// 可滾動、可更新結果集
PreparedStatement pstmt = conn.prepareStatement(sql,
    ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet rs = pstmt.executeQuery();
rs.last(); // 移動到最後一行
rs.beforeFirst(); // 移動到首行前

5. MySQL 8.0+ 關鍵連接參數

jdbc:mysql://localhost:3306/db?
    useSSL=false&                 # 開發環境關閉 SSL
    serverTimezone=UTC&           # 解決時區報錯
    characterEncoding=utf8&       # 字符編碼
    allowPublicKeyRetrieval=true& # 缓存 sha256 密碼插件公鑰
    rewriteBatchedStatements=true # 批處理優化(關鍵性能參數)

四、從 DriverManager 到連接池:生產級升級

DriverManager.getConnection() 每次建立物理連接,開銷極大,生產環境嚴禁使用。

引入 HikariCP(Spring Boot 默認、性能最強)

<dependency>
    <groupId>com.zaxxer</groupId>
    <artifactId>HikariCP</artifactId>
    <version>5.0.1</version>
</dependency>

連接池配置類

public class DataSourceConfig {
    public static HikariDataSource createDataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl(URL);
        config.setUsername(USER);
        config.setPassword(PASS);
        config.setMaximumPoolSize(20);           // 最大連接數
        config.setMinimumIdle(5);                // 最小空閒
        config.setIdleTimeout(300000);           // 空閒超時 5 分鐘
        config.setConnectionTimeout(30000);      // 獲取連接超時 30 秒
        config.setMaxLifetime(1800000);          // 連接最大壽命 30 分鐘
        config.setPoolName("MyApp-Pool");
        config.addDataSourceProperty("cachePrepStmts", "true");
        config.addDataSourceProperty("prepStmtCacheSize", "250");
        config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
        return new HikariDataSource(config);
    }
}

使用連接池

// 單例持有 DataSource
DataSource ds = DataSourceConfig.createDataSource();

// 業務代碼
try (Connection conn = ds.getConnection();  // 從池獲取
     PreparedStatement pstmt = conn.prepareStatement(sql)) {
    // ...
} // 歸還連接池,而非關閉物理連接

五、MyEclipse 具體配置步驟(補充)

  1. 右鍵項目 → Build Path → Configure Build Path → Libraries → Add External JARs
  2. 選擇 mysql-connector-java-x.x.x.jar(MySQL 8.0+ 用 mysql-connector-j)
  3. 項目下出現 Referenced Libraries 節點表示成功
  4. Run As → Java Application 運行主類

URL配置截圖 字段映射截圖 添加JAR截圖 Referenced Libraries截圖 運行結果截圖

六、常見錯誤與解決

  • Build Path 添加 JAR
  • Maven 項目添加 dependency
  • 檢查 3306 端口、bind-address=0.0.0.0
  • URL 加 allowPublicKeyRetrieval=true
  • URL 加 serverTimezone=UTC 或 Asia/Shanghai
  • URL characterEncoding=utf8、表/庫/連接均 UTF-8
  • 錯誤 原因 解決
    ClassNotFoundException 驅動 JAR 未加入 Classpath
    Communications link failure IP/端口錯誤、MySQL 未啟動、防火牆
    Public Key Retrieval is not allowed MySQL 8.0 默認 caching_sha2_password
    Server returns invalid timezone 時區未指定
    中文亂碼 字符編碼不一致

    七、總結

    • JDBC 六步法是基石,PreparedStatement + try-with-resources + 事務控制 是生產代碼標準姿勢
    • MySQL 8.0+ 連接串必加 serverTimezone、allowPublicKeyRetrieval、rewriteBatchedStatements
    • DriverManager 僅供學習/測試,生產必上連接池(HikariCP 首選)
    • 連接池核心參數:最大/最小連接數、超時時間、壽命、預編譯緩存
    • 規範資源關閉順序:ResultSet → Statement → Connection(或 try-with-resources 自動管理)

    掌握 JDBC 核心 API 與連接池原理,是通往 MyBatis、JPA、Spring Data 等 ORM 框架深度理解的基石。

    1. 上一篇文章:
    2. 下一篇文章:
    Copyright © 程式碼之家 All Rights Reserved