应优先选用PreparedStatement;仅在无需参数、仅执行一次且结构完全动态的极少数场景才考虑Statement。它能防止SQL注入、提升同构SQL性能、增强可维护性与类型安全,而Statement仅适用于DDL等无参场景。

绝大多数情况下,应该优先选 PreparedStatement;只有极少数明确不需参数、仅执行一次且结构完全动态的场景,才考虑用 Statement。
安全性:防 SQL 注入是硬性门槛
只要 SQL 中涉及用户输入(如表单、URL 参数、API 请求体),就必须用 PreparedStatement。它把 SQL 结构和参数彻底分离——数据库在预编译阶段就锁定了语句骨架,后续传入的参数只当数据处理,不会被解析为 SQL 代码。
- Statement 拼接字符串:用户名输
' OR '1'='1,可能变成WHERE name = '' OR '1'='1',直接绕过验证 - PreparedStatement 占位符:无论输入什么,
setString(1, " ' OR '1'='1 ")都只会查一个叫这个完整字符串的用户名
性能:同构 SQL 场景下优势明显
“同构 SQL”指语句结构固定、仅参数值变化,比如反复执行 SELECT * FROM order WHERE status = ? AND user_id = ?。
- PreparedStatement 在首次执行时完成编译,数据库缓存执行计划;后续调用只替换参数,跳过词法/语法分析、优化路径选择等耗时步骤
- Statement 每次都重新编译,即使语句看起来一样,因字符串内容不同(如
...user_id = 1001vs...user_id = 1002),数据库无法复用计划 - 批量操作(
addBatch()/executeBatch())几乎只对 PreparedStatement 有效
可维护性与类型安全:写得清楚,错得明白
拼接 SQL 容易出引号错位、类型转换遗漏、空值处理缺失等问题;PreparedStatement 用方法名明确表达语义,由 JDBC 驱动自动处理格式和空值。
立即学习“Java免费学习笔记(深入)”;
-
pstmt.setString(1, name)自动加引号、转义特殊字符 -
pstmt.setInt(2, age)拒绝非数字输入,抛出明确异常,而不是让数据库报语法错误 - SQL 主体干净无变量,逻辑和数据分离,多人协作或后期排查更直观
Statement 的合理使用场景
它不是“错误”,而是适用面窄:
- 执行 DDL 语句(如
CREATE TABLE、DROP INDEX),这类语句通常不带参数,且不常重复执行 - 调试或工具类代码中临时构造简单查询,比如
"SELECT COUNT(*) FROM " + tableName,且表名来自可信配置而非用户输入 - 某些极端动态场景,如根据元数据生成异构 SQL(不同表、不同字段组合),但此时更推荐用 MyBatis 等框架封装,而非裸写 Statement


















