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

JDBC 三大 Statement 類型深度解析與實戰對比

     編輯:Java 相關知識

概覽

JDBC 提供三種執行 SQL 的接口,各有適用場景:

類型繼承關係核心優勢典型場景
Statement基礎接口簡單、無預編譯靜態 SQL、一次性查詢
PreparedStatementextends Statement預編譯、參數化、防注入重複執行、動態參數
CallableStatementextends PreparedStatement調用存儲過程、支持 OUT 參數存儲過程、複雜業務邏輯

Statement - 基礎用法

public void listStudents() throws SQLException {
    // 1. 加載驅動(JDBC 4.0+ 可省略)
    Class.forName("jdbc.odbc.JdbcOdbcDriver");
    
    // 2. 建立連接
    Connection conn = DriverManager.getConnection(
        "jdbc:odbc:StudentDB", "admin", "sa");
    
    // 3. 創建 Statement
    Statement stmt = conn.createStatement();
    
    // 4. 執行查詢
    ResultSet rs = stmt.executeQuery(
        "SELECT StudentID, FirstName, LastName FROM Students");
    
    // 5. 處理結果集
    System.out.println("Student Number | First Name | Last Name");
    while (rs.next()) {
        String id = rs.getString(1);
        String first = rs.getString(2);
        String last = rs.getString(3);
        System.out.printf("%s | %s | %s%n", id, first, last);
    }
    
    // 6. 關閉資源(建議使用 try-with-resources)
    rs.close();
    stmt.close();
    conn.close();
}

更新操作示例

public void updateStudentName(String first, String last, String id) 
        throws SQLException, ClassNotFoundException {
    Connection conn = DriverManager.getConnection(
        "jdbc:odbc:StudentDB", "admin", "sa");
    Statement stmt = conn.createStatement();
    
    // 風險:字符串拼接易導致 SQL 注入
    String sql = "UPDATE Students SET FirstName = '" + first 
               + "', LastName = '" + last 
               + "' WHERE StudentNumber = " + id;
    
    int rows = stmt.executeUpdate(sql);
    System.out.println("Updated " + rows + " rows");
}

PreparedStatement - 參數化查詢最佳實踐

// 類級別連接與預編譯語句(連接池環境下推薦)
private Connection conn;
private PreparedStatement pstmt;
private boolean initialized = false;

private void initConnection() throws SQLException, ClassNotFoundException {
    Class.forName("jdbc.odbc.JdbcOdbcDriver");
    conn = DriverManager.getConnection("jdbc:odbc:StudentDB", "admin", "sa");
    // 1. SQL 預編譯,? 為佔位符
    pstmt = conn.prepareStatement(
        "SELECT ClassName, Location, DaysAndTimes FROM Classes WHERE ClassName = ?");
    initialized = true;
}

public void listOneClass(String className) throws SQLException {
    if (!initialized) initConnection();
    
    // 2. 綁定參數(索引從 1 開始)
    pstmt.setString(1, className);
    
    // 3. 執行查詢
    ResultSet rs = pstmt.executeQuery();
    while (rs.next()) {
        System.out.printf("%s | %s | %s%n", 
            rs.getString(1), rs.getString(2), rs.getString(3));
    }
    rs.close();
}

核心優勢

  • 性能:DB 端解析、編譯、優化僅執行一次
  • 安全:參數綁定徹底防止 SQL 注入
  • 可讀性:SQL 與數據分離,代碼更清晰
  • 類型安全:setInt/setDate 等強類型方法

CallableStatement - 存儲過程調用

public void displayGrade(String studentId, String classId) throws SQLException {
    Class.forName("jdbc.odbc.JdbcOdbcDriver");
    Connection conn = DriverManager.getConnection(
        "jdbc:odbc:studentDB", "admin", "sa");
    
    // 1. 準備調用:{? = call proc_name(?, ?)}
    CallableStatement cstmt = conn.prepareCall(
        "{? = call getStudentGrade(?, ?)}");
    
    // 2. 註冊 OUT 參數(返回值)
    cstmt.registerOutParameter(1, Types.INTEGER);
    
    // 3. 設置 IN 參數
    cstmt.setString(2, studentId);  // 索引 2 對應第一個 ?
    cstmt.setString(3, classId);    // 索引 3 對應第二個 ?
    
    // 4. 執行
    cstmt.executeUpdate();  // 或 execute()
    
    // 5. 獲取返回值
    int grade = cstmt.getInt(1);
    System.out.println("The Grade is: " + grade);
    
    cstmt.close();
    conn.close();
}

參數索引規則

  • OUT 參數(返回值)索引為 1
  • IN/INOUT 參數索引從 2 開始順序遞增
  • 使用 registerOutParameter(index, sqlType) 聲明輸出參數類型

資源管理最佳實踐(JDBC 4.1+)

// try-with-resources 自動關閉
public void queryWithAutoClose(String className) {
    String sql = "SELECT * FROM Classes WHERE ClassName = ?";
    try (Connection conn = DriverManager.getConnection(URL, USER, PASS);
         PreparedStatement pstmt = conn.prepareStatement(sql)) {
        
        pstmt.setString(1, className);
        try (ResultSet rs = pstmt.executeQuery()) {
            while (rs.next()) {
                // 處理數據
            }
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

總結選型指南

  1. Statement:僅用於極簡單、無參數、不重複執行的靜態 SQL
  2. PreparedStatement:90%+ 場景的首選,所有參數化查詢/更新
  3. CallableStatement:必須調用存儲過程時使用,特別是需要返回值或 OUT 參數時

現代項目建議結合連接池(HikariCP/Druid)與 ORM 框架(MyBatis/JPA)使用,直接操作 JDBC 僅在極少量底層優化場景出現。

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