preparedstatement 可安全复用同一对象,前提是 connection 有效且未关闭、sql 模板固定为含 ? 占位符的字符串、未显式调用 close()、每次执行前重设所有参数;它非线程安全,不可多线程共享。

PreparedStatement 可以安全复用同一个对象,前提是它没有被关闭,且对应的 Connection 仍有效。复用的核心在于:**不重复创建,而是多次调用 setXxx() + executeQuery() 或 executeUpdate()**。
复用的前提条件
要成功复用一个 PreparedStatement 实例,必须满足以下几点:
- 该 PreparedStatement 是通过
Connection.prepareStatement(sql)创建的,且 SQL 模板中只含?占位符(不能动态拼接 SQL 字符串) - Connection 未关闭,也未进入无效状态(如网络断开、事务超时等)
- PreparedStatement 本身未显式调用
close() - 每次执行前,都重新设置所有参数(即使部分参数值不变,也建议显式设置,避免残留旧值影响逻辑)
典型复用写法(推荐)
下面是一个在循环中复用 PreparedStatement 的常见场景(如批量插入):
String sql = "INSERT INTO users (name, age) VALUES (?, ?)";
PreparedStatement ps = conn.prepareStatement(sql);
for (User user : userList) {
ps.setString(1, user.getName()); // 每次覆盖参数
ps.setInt(2, user.getAge());
ps.addBatch(); // 或 ps.executeUpdate(),视需求而定
}
ps.executeBatch();
ps.close(); // 最后统一关闭
注意:这里没有在每次循环里 conn.prepareStatement(...),而是复用 ps 对象,仅更新参数并执行。
哪些情况会导致复用失败?
以下操作会中断复用,需特别留意:
-
调用了
ps.close():之后再调用setXxx()或executeXxx()会抛出 SQLException("Statement closed") - Connection 被关闭或失效:PreparedStatement 依赖底层连接,连带失效
-
SQL 模板变更:PreparedStatement 绑定的是原始 SQL 字符串,无法切换成另一条语句(比如想用同一对象执行
SELECT和UPDATE),必须另建新实例 -
数据库驱动或连接池限制:某些老旧驱动或配置严格的连接池(如 HikariCP 的
maxLifetime过短)可能导致 PreparedStatement 提前失效,但这是环境问题,非代码逻辑错误
线程安全提醒
PreparedStatement **不是线程安全的**。多个线程不能共享同一个 PreparedStatement 实例并发调用 setXxx() 或 executeXxx(),否则参数可能错乱或抛出异常。如需多线程使用,应为每个线程分配独立的 PreparedStatement(可复用其所属的 Connection,但 Statement 本身不共享)。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











