| 維度 | Statement | PreparedStatement |
|---|---|---|
| SQL 編譯 | 每次執行都編譯 | 預編譯一次,多次復用 |
| 計劃緩存 | 不緩存 | DB 自動緩存執行計劃 |
| 參數傳遞 | 字符串拼接 | 佔位符 ? 綁定 |
| SQL 注入防護 | 無 | 自動轉義,有效防禦 |
| 代碼可讀性 | 拼接字符串難維護 | 結構清晰,參數分離 |
// 環境:Oracle + JDBC,批量提交閾值 250
@Test
void testPreparedStatementBatch() { // 470 ms
String sql = "insert into dept values(?,?)";
PreparedStatement ps = conn.prepareStatement(sql);
for (int i = 0; i < 100000; ++i) {
ps.setInt(1, i+1);
ps.setString(2, "dept_" + (i+1));
ps.addBatch();
if ((i+1) % 250 == 0) { ps.executeBatch(); ps.clearBatch(); }
}
}
@Test
void testStatementBatch() { // 98,000 ms
Statement st = conn.createStatement();
for (int i = 0; i < 100000; ++i) {
String sql = "insert into dept values(" + (i+1) + ",'dept_" + (i+1) + "')";
st.addBatch(sql);
if ((i+1) % 250 == 0) { st.executeBatch(); st.clearBatch(); }
}
}
結論:PreparedStatement 批量插入比 Statement 快 200 倍以上,主要得益於預編譯計劃復用與網絡交互減少。
// Statement 風險示例
String sql = "SELECT * FROM user WHERE name = '" + userInput + "'";
// 輸入 ' OR '1'='1 導致永真條件
// PreparedStatement 安全
String sql = "SELECT * FROM user WHERE name = ?";
ps.setString(1, userInput); // 參數作為數據傳遞,不參與 SQL 解析
完整 JUnit 測試代碼見原文,涵蓋四種場景對比: