JDBC中prepareStatement 与createStatement 区别

本文对比了使用预编译SQL(prepareStatement)和动态SQL(createStatement)的方法,详细解释了预编译SQL如何通过参数化查询提高数据库访问效率,并指出了其无法预编译表名等局限性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简单来说,prepareStatement 提供预编译SQL语句,可以用"?" 来替换需要改变的参数值,类似于正则化 SQL查询语句。

createStatement则不提供预编译SQL,需要实时executeQuery(sqlStr) 来访问数据库。 因此,prepareStatement可以多次使用,提高访问数据库的效率。


具体可以参考:http://blog.youkuaiyun.com/jiangwei0910410003/article/details/26143977 


Code Fragment 1:

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. String updateString = "UPDATE COFFEES SET SALES = 75 " + "WHERECOF_NAME LIKE ′Colombian′";  
  2. stmt.executeUpdate(updateString);  
Code Fragment 2:
[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. PreparedStatement updateSales = con.prepareStatement("UPDATE COFFEES SETSALES = ? WHERE COF_NAME LIKE ? ");  
  2. updateSales.setInt(175);  
  3. updateSales.setString(2"Colombian");  
  4. updateSales.executeUpdate();  


然而,prepareStatement 也有局限性,并不能修改类似表名。

[java]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. PreparedStatement updateSales = con.prepareStatement("SELECT * FROM ? WHERE COF_NAME LIKE ? ");  
  2. updateSales.setInt(1,"TableName");  
  3. updateSales.setString(2"Colombian");  
  4. ResultSet rs = updateSales.executeQuery();  
会报错,

SQL查询语句为“SELECT * FROM  ‘TableName’ WHERE COF_NAME LIKE ‘Colombian’  ”

<think>我们正在讨论JDBC中执行SQL的方式,除了PreparedStatement之外,还有其他方式。根据引用[2][3],我们知道JDBC中主要有两种执行SQL的接口:StatementPreparedStatement。另外,还有一个CallableStatement用于执行存储过程。因此,我们可以这样回答: 用户询问的是除了PreparedStatement之外,JDBC中还有哪些执行SQL的方法。根据已有的引用JDBC知识,我们可以总结如下: 1. **Statement**:最基本的SQL执行接口,用于执行静态SQL语句。它没有预编译功能,每次执行都需要将SQL语句发送给数据库解析。因此,如果多次执行相同的SQL(只是参数不同),效率较低。另外,使用Statement需要注意SQL注入问题,因为它直接将参数拼接在SQL语句中。 示例代码: ```java Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM table"); ``` 2. **PreparedStatement**:预编译的SQL执行接口,可以防止SQL注入,并且对于多次执行相同结构(仅参数不同)的SQL效率更高。它使用占位符(?)来表示参数,然后通过setXXX方法设置参数值。 示例代码: ```java PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM table WHERE id=?"); pstmt.setInt(1, 10); ResultSet rs = pstmt.executeQuery(); ``` 3. **CallableStatement**:用于执行数据库中的存储过程。它继承自PreparedStatement,除了支持输入参数外,还支持输出参数输入输出参数。 示例代码: ```java CallableStatement cstmt = conn.prepareCall("{call my_stored_procedure(?, ?)}"); cstmt.setInt(1, 10); // 设置输入参数 cstmt.registerOutParameter(2, Types.VARCHAR); // 注册输出参数 cstmt.execute(); String result = cstmt.getString(2); // 获取输出参数的值 ``` 另外,需要注意的是,StatementPreparedStatement都支持执行不同类型的SQL: - 对于查询(SELECT),使用`executeQuery`方法,返回ResultSet。 - 对于更新(INSERT, UPDATE, DELETE),使用`executeUpdate`方法,返回受影响的行数。 - 对于不确定是查询还是更新的语句,或者执行DDL(如CREATE TABLE),可以使用`execute`方法,然后通过`getResultSet`或`getUpdateCount`获取结果。 此外,从Java 7开始,这些接口都实现了AutoCloseable,因此可以使用try-with-resources自动关闭资源。 总结,除了PreparedStatement,还有StatementCallableStatement。它们的关系如下: - Statement:基本语句,无参数。 - PreparedStatement:预编译语句,支持输入参数。 - CallableStatement:用于存储过程,支持输入输出参数。 最后,生成相关问题: 1. StatementPreparedStatement的主要区别是什么? 2. 如何使用CallableStatement调用存储过程? 3. 在JDBC中如何防止SQL注入?</think>### JDBC 中执行 SQL 的三种主要方式 在 JDBC 中,除了 `PreparedStatement` 外,还有以下两种核心的 SQL 执行接口: #### 1. **Statement(基础执行器)** - **特点**:直接执行静态 SQL 语句,**不支持预编译参数化查询** - **适用场景**:执行一次性静态 SQL(如 DDL 语句) - **风险**:**存在 SQL 注入漏洞**(需手动拼接参数) - **示例代码**: ```java try (Statement stmt = connection.createStatement()) { String sql = "SELECT * FROM users WHERE name = '" + userName + "'"; // 手动拼接参数 ResultSet rs = stmt.executeQuery(sql); // 执行查询 while (rs.next()) { // 处理结果 } } ``` - **关键方法**: - `executeQuery(String sql)`:执行查询,返回 `ResultSet` - `executeUpdate(String sql)`:执行更新,返回影响行数 - `execute(String sql)`:通用执行方法 #### 2. **CallableStatement(存储过程执行器)** - **特点**:专用于调用数据库**存储过程**,支持输入/输出参数 - **继承关系**:`CallableStatement` → `PreparedStatement` → `Statement` - **参数处理**: - `?` 作为参数占位符 - `registerOutParameter()` 注册输出参数 - **示例代码**: ```java try (CallableStatement cstmt = connection.prepareCall("{call get_user_data(?, ?)}")) { cstmt.setString(1, userId); // 设置输入参数 cstmt.registerOutParameter(2, Types.INT); // 注册输出参数 cstmt.execute(); int result = cstmt.getInt(2); // 获取输出参数 } ``` #### 三种方式对比总结 | **特性** | `Statement` | `PreparedStatement` | `CallableStatement` | |------------------------|---------------------|--------------------------|---------------------------| | **预编译** | ❌ 不支持 | ✅ 支持 | ✅ 支持 | | **SQL 注入防护** | ❌ 高风险 | ✅ 自动转义参数 | ✅ 自动转义参数 | | **参数化支持** | ❌ 需手动拼接 | ✅ 通过 `setXxx()` 设置 | ✅ 支持输入/输出参数 | | **执行效率** | 低(每次解析 SQL) | 高(可复用预编译结果) | 高 | | **典型用途** | DDL 语句 | 动态参数查询/更新 | 调用存储过程 | > 最佳实践推荐:**优先使用 `PreparedStatement`**(安全高效),仅当调用存储过程时使用 `CallableStatement`,避免使用原生 `Statement`[^1][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值