| 優勢 | 說明 |
|---|---|
| 效能提升 | SQL 預編譯,同一條語句多次執行僅編譯一次,批量處理極大降低開銷 |
| 防注入 | 參數化查詢,數據與代碼分離,徹底阻斷 SQL 注入 |
| 可讀性 | 佔位符 ? 替代字串拼接,邏輯清晰 |
| 型別安全 | setInt/setString/setDate 等強類型綁定 |
| Blob/Clob 支援 | 流式讀寫大對象,Statement 難以勝任 |
一次性查詢用
Statement亦可,但習慣統一用PreparedStatement更安全。
// 1. 獲取預編譯對象
PreparedStatement ps = conn.prepareStatement("SELECT * FROM user WHERE age > ? AND name LIKE ?");
// 2. 綁定參數 (索引從 1 開始)
ps.setInt(1, 18);
ps.setString(2, "Zhang%");
// 3. 執行
ResultSet rs = ps.executeQuery(); // 查詢
int count = ps.executeUpdate(); // 增刪改
boolean hasResult = ps.execute(); // 通用
// 4. 批量處理
for (User u : users) {
ps.setString(1, u.getName());
ps.setInt(2, u.getAge());
ps.addBatch();
}
int[] results = ps.executeBatch(); // 返回各條影響行數
public ResultSet queryByRange(String sql, String min, String max) {
getConnection();
try {
ps = conn.prepareStatement(sql);
ps.setString(1, min);
ps.setString(2, max);
return ps.executeQuery();
} catch (SQLException e) { e.printStackTrace(); }
return null;
}
public ResultSet query(String sql, Object... params) {
getConnection();
try {
ps = conn.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
for (int i = 0; i < params.length; i++) {
ps.setObject(i + 1, params[i]); // setObject 自動適配類型
}
return ps.executeQuery();
} catch (SQLException e) { e.printStackTrace(); }
return null;
}
// 調用
query("SELECT * FROM t_user WHERE birth_year BETWEEN ? AND ?", "1992", "1992");
query("SELECT * FROM t_user WHERE id BETWEEN ? AND ?", 100, 200);
public int executeUpdate(String sql, Object... params) {
int count = 0;
getConnection();
try {
ps = conn.prepareStatement(sql);
if (params != null) {
for (int i = 0; i < params.length; i++) {
ps.setObject(i + 1, params[i]);
}
}
count = ps.executeUpdate();
} catch (SQLException e) { e.printStackTrace(); }
finally { close(); }
return count;
}
// 批量新增
for (int i = 0; i < 10; i++) {
executeUpdate("INSERT INTO jdbc_test(username, password) VALUES(?,?)", "user" + i, "pwd" + i);
}
// 範圍刪除
executeUpdate("DELETE FROM t_user WHERE id BETWEEN ? AND ?", 1010, 1030);
public Object[][] toArray(ResultSet rs) {
try {
rs.last();
int rows = rs.getRow();
ResultSetMetaData meta = rs.getMetaData();
int cols = meta.getColumnCount();
rs.beforeFirst();
Object[][] data = new Object[rows][cols];
int r = 0;
while (rs.next()) {
for (int c = 0; c < cols; c++) {
data[r][c] = rs.getObject(c + 1);
}
r++;
}
return data;
} catch (SQLException e) { e.printStackTrace(); return new Object[0][0]; }
}
setObject 雖通用,但某些驅動對時間類型支援不佳,優先用專用 setDate/setTimestampclearBatch() 避免內存洩漏ResultSet.TYPE_SCROLL_INSENSITIVE 允許前後移動光標,便於獲取行數,但消耗更大