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 ที่ใช้บ่อย
| เมธอด | ชนิดข้อมูล Java | ชนิดข้อมูล SQL |
setString(int, String) | String | VARCHAR, CHAR, TEXT |
setInt(int, int) | int | INT, SMALLINT |
setLong(int, long) | long | BIGINT |
setDouble(int, double) | double | DOUBLE, FLOAT |
setBigDecimal(int, BigDecimal) | BigDecimal | DECIMAL, NUMERIC |
setDate(int, Date) | java.sql.Date | DATE |
setTimestamp(int, Timestamp) | java.sql.Timestamp | TIMESTAMP, DATETIME |
setBoolean(int, boolean) | boolean | BOOLEAN, BIT |
setNull(int, int sqlType) | - | NULL |
การ 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
- ป้องกัน SQL Injection: ค่าพารามิเตอร์ถูก Escape อัตโนมัติ
- ประสิทธิภาพดีกว่า: Query ถูก Parse/Compile/Optimize เพียงครั้งเดียว
- Batch Processing:
addBatch() + executeBatch() เร็วมากสำหรับ Bulk Insert
- Type Safety: ตรวจสอบชนิดข้อมูลตอน Compile
- อ่านง่าย/บำรุงรักษาง่าย: แยก 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]));
}