在 Java 資料庫開發中,PreparedStatement 是提升 SQL 執行效率、防範 SQL 注入攻擊的核心工具。本文將從原理優勢、核心代碼實現、進階擴展模式三個維度,系統闡述預編譯技術的綜合應用。
PreparedStatement 物件將 SQL 語句預編譯並緩存於資料庫端,後續多次執行時僅需傳遞參數,無需重複解析、編譯、優化流程。其核心優勢體現在:
選型建議:單次執行的臨時查詢可用Statement;多次執行、帶參數查詢、批量操作強制使用PreparedStatement。
// 預編譯方式構建 SQL 查詢
String sql = "select * from student where year(birthday) between ? and ?";
PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, "1987");
ps.setString(2, "1990");
ResultSet rs = ps.executeQuery();
/** PreparedStatement 預編譯之查詢範圍 */
public ResultSet startQuery(String sql, String param1, String param2) {
getConnection();
try {
pStatement = connection.prepareStatement(sql);
pStatement.setString(1, param1);
pStatement.setString(2, param2);
rSet = pStatement.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
return rSet;
}
針對不固定參數數量的查詢場景,使用 Object[] 陣列實現通用化:
/** PreparedStatement 預編譯之查詢擴展版 */
public ResultSet startQueryLook(String sql, Object[] params) {
getConnection();
try {
pStatement = connection.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
pStatement.setObject(i + 1, params[i]);
}
rSet = pStatement.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
return rSet;
}
// 生日範圍查詢
String[] birthParams = {"1992", "1992"};
ResultSet rs1 = dao.startQueryLook(
"select * from t_userr where year(birthdate) between ? and ?",
birthParams
);
// ID 範圍查詢
String[] idParams = {"100", "200"};
ResultSet rs2 = dao.startQueryLook(
"select * from t_userr where id between ? and ?",
idParams
);
/** PreparedStatement 預編譯之增刪改擴展版 */
public int startQueryAll(String sql, Object[] params) {
int count = 0;
getConnection();
try {
pStatement = connection.prepareStatement(sql);
if (params != null && params.length > 0) {
for (int i = 0; i < params.length; i++) {
pStatement.setObject(i + 1, params[i]);
}
}
count = pStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
close();
}
return count;
}
// 批次新增 10 條測試資料
for (int i = 0; i < 10; i++) {
Object[] insertParams = {"user" + i, "pass" + i};
dao.startQueryAll(
"insert into jdbctest(username, password) values(?, ?)",
insertParams
);
}
// 批次刪除 ID 區間資料
dao.startQueryAll(
"delete from t_userr where id between ? and ?",
new Object[]{"1010", "1030"}
);
setXxx() 方法綁定參數,禁止字串拼接 SQL。finally 區塊關閉 Connection、PreparedStatement、ResultSet,防止連線洩漏。addBatch() + executeBatch() 替代循環執行。掌握 PreparedStatement 的預編譯機制與靈活封裝技巧,能顯著提升 JDBC 應用的效能、安全性與可維護性,是 Java 後端開發必備的核心技能。