MySQL - 动态SQL与预处理语句

本文介绍如何在存储过程或函数中使用动态SQL及预处理语句来提高SQL执行效率并防止SQL注入。详细解释了如何通过变量动态生成SQL语句,并演示了预处理语句的具体用法。

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

在存储过程或者函数中,有时SQL语句是通过变量传值生成的。这时候就需要使用动态SQL,如果直接在SQL语句中植入变量,将提示无该字段或表。

如下所示:

v_db 和v_table均是变量传值动态生成。

create table v_table like  v_db.v_table;

直接执行将提示错误。

这里写图片描述


【动态SQL】

动态SQL示例如下(在存储过程中使用):

CREATE  PROCEDURE `proc_copy_table`(IN v_table VARCHAR(20),IN v_db VARCHAR(20),OUT o_result int(4))
BEGIN
    DECLARE exit HANDLER FOR SQLEXCEPTION  
    begin
        rollback; -- 有异常,进行回滚
        set o_result = -500;
    end;

    START TRANSACTION;
        SET @sql1 = CONCAT('drop table if EXISTS ',v_table,';');
        -- drop table if EXISTS v_table;
      prepare stmt from @sql1;  -- 预处理需要执行的动态SQL,
        EXECUTE stmt;
        deallocate prepare stmt;     -- 释放掉预处理段


        set @sql2 = CONCAT('create table ',v_table,' like ',v_db,'.',v_table,';');
        -- create table v_table like  v_db.v_table;
        prepare stmt from @sql2;  -- 预处理需要执行的动态SQL,
        EXECUTE stmt;
        deallocate prepare stmt;     -- 释放掉预处理段

        set @sql3 = CONCAT('insert into  ',v_table,' select * from  ',v_db,'.',v_table,';');
        -- insert into v_table select * from v_db.v_table;
        prepare stmt from @sql3;  -- 预处理需要执行的动态SQL,
        EXECUTE stmt;
        deallocate prepare stmt;     -- 释放掉预处理段
  COMMIT;
    set o_result :=0;
end

这里动态SQL的生成说明如下:

使用concat拼接,将变量传值进去:

SET @sql1 = CONCAT('drop table if EXISTS ',v_table,';');

-- 效果如下:
 drop table if EXISTS [v_table实际变量值];

【预处理语句】

MySQL官方将prepare、execute、deallocate统称为PREPARE STATEMENT。

即,预处理语句。

其用法十分简单:

//获取预处理语句
PREPARE stmt_name FROM preparable_stmt;

//执行预处理语句(可传入用户变量)
EXECUTE stmt_name
    [USING @var_name [, @var_name] ...];

//释放掉预处理资源
{DEALLOCATE | DROP} PREPARE stmt_name;

使用PAREPARE STATEMENT可以减少每次执行SQL的语法分析,

比如用于执行带有WHERE条件的SELECT和DELETE,或者UPDATE,或者INSERT,只需要每次修改变量值即可。

同样可以防止SQL注入,参数值可以包含转义符和定界符。

PREPARE … FROM可以直接接用户变量:

    SET @sql1 = CONCAT('drop table if EXISTS ',v_table,';');

      prepare stmt from @sql1;  -- 预处理需要执行的动态SQL,

每一次执行完EXECUTE时,养成好习惯,须执行DEALLOCATE PREPARE …语句,这样可以释放执行中使用的所有数据库资源(如游标)。

不仅如此,如果一个session的预处理语句过多,可能会达到max_prepared_stmt_count的上限值。

预处理语句只能在创建者的会话中可以使用,其他会话是无法使用的。而且在任意方式(正常或非正常)退出会话时,之前定义好的预处理语句将不复存在。

如果在存储过程中使用,如果不在过程中DEALLOCATE掉,在存储过程结束之后,该预处理语句仍然会有效。

### SQL预处理语句的用法实现 #### 预处理语句概述 SQL预处理语句(Prepared Statements)是一种被广泛应用于成熟数据库中的技术,允许开发者创建一种类似于模板的SQL语句结构。这种语句可以通过绑定不同的参数来动态调整其行为,从而提高性能并增强安全性[^3]。 #### 使用场景优势 预处理语句的主要优点在于能够减少重复解析SQL语句的时间开销以及防止SQL注入攻击。通过预先定义好SQL语句的形式,在后续操作中仅需替换其中的占位符即可完成多次查询或更新操作。 #### 基本构成部分 在MySQL环境下,预处理语句的操作流程主要包括以下几个阶段: - **PREPARE**: 准备待执行的SQL语句- **EXECUTE**: 执行已准备好的SQL语句,并传递实际参数值。 - **DEALLOCATE PREPARE**: 清除不再使用的预处理语句资源[^2]。 以下是具体的语法说明及示例: #### 语法描述 1. `PREPARE`命令用于命名一条即将被执行的SQL语句,并指定该语句的具体形式; 2. `EXECUTE`则负责调用之前由`PREPARE`所建立起来的那个名字对应的SQL逻辑体,同时提供必要的输入数据作为参数传入; 3. 当不需要再继续利用某个特定名称关联着的一系列动作时,则可通过发出`DEALLOCATE PREPARE`指令释放相关联内存空间其他计算成本。 #### 实现案例分析 下面给出一段关于如何运用上述机制的一个简单例子——向表student里插入新记录的过程演示如下所示: ```sql -- Step 1: Prepare the statement with placeholders (? represents parameters) PREPARE stmt FROM 'INSERT INTO student (name, age) VALUES (?, ?)' ; -- Step 2: Execute prepared statement multiple times by providing different values each time. SET @sName = 'John Doe'; SET @nAge = 20; EXECUTE stmt USING @sName ,@nAge; SET @sName = 'Jane Smith'; SET @nAge = 22; EXECUTE stmt USING @sName ,@nAge; -- Step 3: Once done executing all required instances of this query pattern, deallocate it to free resources. DEALLOCATE PREPARE stmt ; ``` 此脚本展示了怎样构建一个可重用的insert模式并通过改变所提供的具体姓名年龄组合达到批量录入目的的同时还注意到了最后一步清理工作的重要性以确保不会浪费系统级别的宝贵资产如CPU周期或者RAM容量等等[^1]^.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值