Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> MySQL

PreparedStatement ใน JDBC คืออะไร และการใช้งาน

PreparedStatement เป็น Interface ที่ extends Statement ใช้สำหรับ SQL ที่มีพารามิเตอร์ (Parameterized Query) คอมไพล์ไว้ล่วงหน้า ใช้งานซ้ำได้ ป้องกัน SQL Injection

การสร้าง PreparedStatement

String query = "INSERT INTO Employee(Name, Salary, Location) VALUES (?, ?, ?)";
PreparedStatement pstmt = con.prepareStatement(query);

ตั้งค่าพารามิเตอร์ (Parameter Binding)

// เซตค่าให้ Placeholder (?) ตามลำดับ (1-based index)
pstmt.setString(1, "Amit");      // ? แรก
pstmt.setInt(2, 30000);          // ? ที่สอง
pstmt.setString(3, "Hyderabad"); // ? ที่สาม

// เซตค่าครั้งที่ 2 (ใช้ซ้ำ Statement เดียวกัน)
pstmt.setString(1, "Kalyan");
pstmt.setInt(2, 40000);
pstmt.setString(3, "Vishakhapatnam");

เมธอด Setter ที่ใช้บ่อย

การ Execute

  • execute() - boolean, ใช้ได้ทุกประเภท
  • executeQuery() - ResultSet, ใช้กับ SELECT
  • executeUpdate() - int (row count), ใช้กับ INSERT/UPDATE/DELETE/DDL

ตัวอย่างครบถ้วน: INSERT หลายแถว

import java.sql.*;

public class PreparedStatementExample {
    public static void main(String[] args) {
        String url = "jdbc:mysql://localhost:3306/testdb?useSSL=false";
        String user = "root";
        String password = "password";
        
        String sql = "INSERT INTO Employees(Name, Salary, Location) VALUES (?, ?, ?)";
        
        try (Connection con = DriverManager.getConnection(url, user, password);
             PreparedStatement pstmt = con.prepareStatement(sql)) {
            
            // Batch Insert - ประหยัด Round-trip
            String[][] employees = {
                {"Amit", "30000", "Hyderabad"},
                {"Kalyan", "40000", "Vishakhapatnam"},
                {"Renuka", "50000", "Delhi"},
                {"Archana", "15000", "Mumbai"}
            };
            
            for (String[] emp : employees) {
                pstmt.setString(1, emp[0]);
                pstmt.setInt(2, Integer.parseInt(emp[1]));
                pstmt.setString(3, emp[2]);
                pstmt.addBatch();  // เพิ่มเข้า Batch
            }
            
            int[] results = pstmt.executeBatch(); // Execute ทั้งหมดครั้งเดียว
            System.out.println("Rows inserted: " + results.length);
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

ข้อดีของ PreparedStatement

  1. ป้องกัน SQL Injection: ค่าพารามิเตอร์ถูก Escape อัตโนมัติ
  2. ประสิทธิภาพดีกว่า: Query ถูก Parse/Compile/Optimize เพียงครั้งเดียว
  3. Batch Processing: addBatch() + executeBatch() เร็วมากสำหรับ Bulk Insert
  4. Type Safety: ตรวจสอบชนิดข้อมูลตอน Compile
  5. อ่านง่าย/บำรุงรักษาง่าย: แยก SQL Logic กับ Data

⚠️ ข้อจำกัด

  • ไม่สามารถใช้ Placeholder สำหรับ Table Name, Column Name, SQL Keywords ได้
  • IN (?) ไม่รองรับ List โดยตรง ต้องสร้าง Placeholder จำนวนเท่ากับสมาชิก

งานรอบๆ IN Clause

// ผิด: pstmt.setString(1, "1,2,3,4"); // จะถูก Escape กลายเป็น '1,2,3,4'

// ถูก: สร้าง Placeholder จำนวนพอดี
String ids = "1,2,3,4";
String[] idArray = ids.split(",");
String placeholders = String.join(",", Collections.nCopies(idArray.length, "?"));
String sql = "SELECT * FROM users WHERE id IN (" + placeholders + ")";

PreparedStatement pstmt = con.prepareStatement(sql);
for (int i = 0; i < idArray.length; i++) {
    pstmt.setInt(i + 1, Integer.parseInt(idArray[i]));
}
เมธอดชนิดข้อมูล Javaชนิดข้อมูล SQL
setString(int, String)StringVARCHAR, CHAR, TEXT
setInt(int, int)intINT, SMALLINT
setLong(int, long)longBIGINT
setDouble(int, double)doubleDOUBLE, FLOAT
setBigDecimal(int, BigDecimal)BigDecimalDECIMAL, NUMERIC
setDate(int, Date)java.sql.DateDATE
setTimestamp(int, Timestamp)java.sql.TimestampTIMESTAMP, DATETIME
setBoolean(int, boolean)booleanBOOLEAN, BIT
setNull(int, int sqlType)-NULL