prapared statement

本文介绍了MySQL 5.1版本引入的服务器端PreparedStatements功能,详细解释了其语法及使用方法,包括如何通过字符串声明和用户变量声明来创建PreparedStatements。此外,还探讨了PreparedStatements的安全性和性能优势,以及它们在存储过程中的应用。

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

 转 :http://blog.youkuaiyun.com/lxgwm2008/article/details/9017587


一:介绍

从 5.1开始,mysql支持服务器端的Prepared Statements,他使用在client/server更有优势的binary protocol,(mysql的传统的协议中,再把数据通过网络传输前,需要把一切数据都转换成strings,这样就比原始数据大很多,最后,在服务器端,还必须把string转化成正确的数据格式。而binary protocol去除了转换的开销,在被传输前,所有类型都转换成本地的binary类型,这样就减少了cpu转换的开销跟网络的使用)在C API/php API中都能支持使用 Prepared Statements,而在交互式的sql接口中也支持,但是他不能使用binary protocol,所以他一般只用在测试或者本地不支持api的情况下。


Prepared Statements的sql语法是基于三个sql 语法
1:PREPARE prepares a statement for execution
2:EXECUTE executes a prepared statement

3:DEALLOCATE PREPARE releases a prepared statement


下面使用使用prepared statement两种的方法来计算直角三角行的斜边
1:使用字符串声明来创建prepared statement
mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> SET @a = 3;
mysql> SET @b = 4;
mysql> EXECUTE stmt1 USING @a, @b;
+------------+
| hypotenuse |
+------------+
|          5 |
+------------+

mysql> DEALLOCATE PREPARE stmt1;


2:跟上面一样,但是使用用户变量来声明
mysql> SET @s = 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> PREPARE stmt2 FROM @s;
mysql> SET @a = 6;
mysql> SET @b = 8;
mysql> EXECUTE stmt2 USING @a, @b;
+------------+
| hypotenuse |
+------------+
|         10 |
+------------+

mysql> DEALLOCATE PREPARE stmt2;


下面的例子是演示:当表名是通过用户变量存储时,如何选择表名来运行query。
mysql> USE test;
mysql> CREATE TABLE t1 (a INT NOT NULL);
mysql> INSERT INTO t1 VALUES (4), (8), (11), (32), (80);

mysql> SET @table = 't1';
mysql> SET @s = CONCAT('SELECT * FROM ', @table);

mysql> PREPARE stmt3 FROM @s;
mysql> EXECUTE stmt3;
+----+
| a  |
+----+
|  4 |
|  8 |
| 11 |
| 32 |
| 80 |
+----+

mysql> DEALLOCATE PREPARE stmt3;


二:为什么要使用 Prepared Statements
在应用程序中,使用Prepared Statements有很多好点,包括安全跟性能原因
1:安全
Prepared Statements通过sql逻辑与数据的分离来增加安全,sql逻辑与数据的分离能防止普通类型的sql注入攻击(SQL injection attack),在一些特殊的query中,提交从客户端那接受来的数据时,应该很注意,在使用麻烦字符(如:single quote, double quote, and backslash characters)时这注意是很有必要的。在这里,Prepared Statements使用不是很有必要,但数据的分离允许MySQL的自动考虑到这些字符,使他们并不需使用任何特殊功能来要转义
2:性能
第一:Prepared Statements只语法分析一次,你初始话Prepared Statements时,mysql将检查语法并准备语句的运行,当你执行query 多次时,这样就不会在有额外的负担了,如果,当运行query 很多次的时候(如:insert)这种预处理有很大的性能提高。
第二:就是上面说的他使用binary protocol协议,这样更能提高效率。
但是我使用Prepared Statements,并不是因为上面两个原因,我是因为在存储过程中,有的语句语法并不能使用动态的变量,(如:select的limit,alter 语句)就只有用 Prepared Statements来解决这个问题了。如:
set @stmt=concat('alter table weekstock add week',@weekname,' int(4)');
prepare s1 from @stmt;
execute s1;
deallocate prepare s1;
三:注意:
如果prepared statement在session级别被新建时,如果你关闭session,就会自动deallocates。在session中也能使用全局的prepared statement,如果你在这存储过程中使用新建prepared statement,当存储过程结束时候,他是不会自动deallocates 故为了限制在瞬间新建大量的prepared statements,mysql通过max_prepared_stmt_count 变量来控制,当设为0时,是限制使用prepared statements.

下面语法能被使用在 prepared statements中: ALTER TABLE, CALL, COMMIT, CREATE INDEX, CREATE TABLE, DELETE, DO, DROP INDEX, DROP TABLE, INSERT, RENAME TABLE, REPLACE, SELECT, SET, UPDATE, and most SHOW statements.例外有的statements 会在后续版本中添加进来。


转自:http://blog.youkuaiyun.com/yq495/article/details/8250352


<think>我们正在讨论预编译SELECT语句(PreparedSelectStatement)在SQL中的应用。根据提供的引用,我们可以总结以下关键点: 1. **预编译语句的基本概念**:预编译语句(Prepared Statement)是一种包含占位符(通常用`?`表示)的SQL语句模板。在创建时,SQL语句中的参数值不指定,而是在执行前通过应用程序设置(引用[1][2])。 2. **预编译语句的优势**:- **防止SQL注入**:通过参数化查询,将用户输入作为参数传递,而不是直接拼接到SQL字符串中,从而避免恶意SQL注入(引用[3])。-**性能提升**:预编译语句可以被数据库预编译并缓存,当多次执行同一语句(仅参数不同)时,可提高执行效率(引用[2])。 3. **在JDBC中的使用**:在Java中,使用`PreparedStatement`接口来执行预编译SQL语句。例如,执行一个带参数的SELECT查询:```javaString sql= "SELECT *FROM productsWHERE productcode =?";PreparedStatement pstmt =connection.prepareStatement(sql);pstmt.setString(1, "S001");//设置第一个参数的值ResultSetrs =pstmt.executeQuery();``` 4. **在JMeter中的使用**:在JMeter的JDBC请求中,也可以使用预编译SELECT语句。有两种方式设置参数(引用[5]):-方法一:使用`${变量名}`引用变量。-方法二:使用占位符`?`,然后在“Parameter values”中按顺序填写参数值。 现在,针对用户的问题“prepared selectstatement inSQL”,我们可以给出以下回答: ###预编译SELECT语句(PreparedSelectStatement)在SQL中的应用预编译SELECT语句是一种参数化的SQL查询方式,它使用占位符(如`?`)代替具体的值,然后在执行前设置这些参数值。这种方式在数据库编程中被广泛使用,特别是在安全性和性能方面有显著优势。 ####1.基本语法在SQL中,预编译SELECT语句的模板如下:```sqlSELECT列名FROM表名WHERE条件列= ?; ```其中,`?`是占位符,代表一个参数。实际执行时,每个`?`都会被具体的参数值替换。 ####2.工作原理- **预编译阶段**:数据库接收到带占位符的SQL语句后,会进行语法解析、优化,并生成执行计划,然后缓存该计划。- **执行阶段**:当应用程序设置具体参数值并执行时,数据库直接使用缓存的执行计划,从而减少重复解析和优化的开销。 ####3.主要优势- **安全性**:由于参数值在预编译后传入,不会改变SQL语句的结构,因此可以有效防止SQL注入攻击(引用[3])。- **性能**:对于需要多次执行的相同SELECT语句(仅参数不同),预编译可以显著提高执行速度(引用[2])。- **可读性与维护性**:参数化查询使代码更清晰,易于维护。####4.在编程中的使用示例以下是在不同环境中使用预编译SELECT语句的示例:**Java (JDBC)**```java//假设已经获得数据库连接Connection对象Stringsql ="SELECTname,price FROMproducts WHEREcategory =? ANDprice >?";PreparedStatement pstmt =conn.prepareStatement(sql); pstmt.setString(1,"Electronics");//设置第一个参数(类别)pstmt.setDouble(2,100.0);//设置第二个参数(价格) ResultSet rs= pstmt.executeQuery();while (rs.next()) {//处理结果集}``` **JMeter(JDBC Request)**在JMeter中配置JDBC请求时:- **Query Type**:选择`PreparedSelect Statement` -**SQLQuery**:填写带`?`的SQL语句- **Parameter values**:填写参数值,多个参数用逗号分隔(如:`Electronics,100.0`) -**Parametertypes**:可以指定参数类型(如:`VARCHAR,DECIMAL`)####5.注意事项- **参数设置顺序**:占位符`?`的顺序必须与设置参数的顺序一致(从左到右,从1开始)。- **参数类型匹配**:设置参数时需确保数据类型与数据库列类型匹配,否则可能抛出异常。- **资源释放**:使用后务必关闭`PreparedStatement`和`ResultSet`以释放数据库资源。###总结预编译SELECT语句是数据库编程中的重要技术,它通过参数化查询提高安全性和性能。在开发中,应优先使用`PreparedStatement`代替普通的`Statement`来执行SQL查询(引用[3])。§§相关问题§§1.预编译SELECT语句在哪些情况下性能提升最明显? 2.除了防止SQL注入,预编译语句还有哪些安全优势? 3.在非SELECT语句(如INSERT、UPDATE)中,预编译语句如何使用? 4.不同数据库(如MySQL、Oracle)对预编译语句的支持有何差异?</think>### 预编译 SELECT 语句(Prepared Select Statement)详解 预编译 SELECT 语句是 SQL 中的一种**参数化查询技术**,通过占位符(`?`)替代具体值,在执行前预编译 SQL 结构,提升安全性和性能。 #### 核心原理 ```sql SELECT * FROM products WHERE productcode = ?; -- 占位符?代替实际参数 ``` 1. **预编译阶段** SQL 模板发送到数据库,数据库解析并优化执行计划,缓存编译结果[^2]。 2. **参数绑定阶段** 程序将具体参数值(如 `"A001"`)绑定到占位符: ```java pstmt.setString(1, "A001"); // JDBC 参数绑定示例 ``` 3. **执行阶段** 数据库直接使用缓存的执行计划执行查询[^1]。 #### 核心优势 1. **安全防注入** - 用户输入始终作为**数据参数**处理,不与 SQL 结构拼接 - 彻底避免 `' OR 1=1 --` 类注入攻击[^3] *示例漏洞:* ```sql -- 普通Statement(危险!) "SELECT * FROM users WHERE name='" + userInput + "'" -- 输入 `admin' -- ` 可绕过验证 ``` 2. **性能提升** - 相同 SQL 模板多次执行时,复用预编译的执行计划 - 减少数据库解析开销,尤其适合循环查询[^2] 3. **代码可读性** - 参数与 SQL 逻辑分离,维护更清晰 #### 具体实现示例 **Java JDBC 代码**: ```java String sql = "SELECT name, price FROM products WHERE category = ? AND stock > ?"; try (PreparedStatement pstmt = conn.prepareStatement(sql)) { pstmt.setString(1, "Electronics"); // 绑定第一个? pstmt.setInt(2, 10); // 绑定第二个? ResultSet rs = pstmt.executeQuery(); // 处理结果集... } ``` **JMeter 配置**(引用[^5]): - **Query Type**: `Prepared Select Statement` - **SQL Query**: `SELECT * FROM users WHERE email = ?` - **Parameter values**: `${test_email}` 或直接值 - **Parameter types**: `VARCHAR` (指定参数类型) #### 适用场景 1. 高频重复查询(如商品搜索) 2. 接受用户输入的查询界面 3. Web 应用数据库操作 4. 批量数据处理任务 > **注意**:预编译语句对动态表名/列名无效(如 `SELECT ? FROM table`),此类场景需结合白名单验证[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值