MySQL SQL预处理(Prepared)的语法实例与注意事项

目录
  • 一、sql 语句的执行处理
    • 1、即时 sql
    • 2、预处理 sql
  • 二、prepared sql statement syntax
    • 三、预处理 sql 使用注意点
      • 四、prepared statements优点
        • 总结

          一、sql 语句的执行处理

          1、即时 sql

          一条 sql 在 db 接收到最终执行完毕返回,大致的过程如下:

            1. 词法和语义解析;

            2. 优化 sql 语句,制定执行计划;

            3. 执行并返回结果;

          如上,一条 sql 直接是走流程处理,一次编译,单次运行,此类普通语句被称作 immediate statements (即时 sql)。

          2、预处理 sql

          但是,绝大多数情况下,某需求某一条 sql 语句可能会被反复调用执行,或者每次执行的时候只有个别的值不同(比如 select 的 where 子句值不同,update 的 set 子句值不同,insert 的 values 值不同)。如果每次都需要经过上面的词法语义解析、语句优化、制定执行计划等,则效率就明显不行了。

          所谓预编译语句就是将此类 sql 语句中的值用占位符替代,可以视为将 sql 语句模板化或者说参数化,一般称这类语句叫prepared statements。

          预编译语句的优势在于归纳为:一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止 sql 注入。

          注意:

          虽然可能是通过预处理 sql 的方式一定程度的提高了效率,但是对于优化而言,最优的执行计划不是光靠 sql 语句的模板化来实现的,往往还是需要通过具体值来预估出成本代价。

          二、prepared sql statement syntax

          mysql 官方将 prepare、execute、deallocate 统称为 prepare statement。翻译也就习惯的称其为预处理语句。

          mysql 预处理语句的支持版本较早,所以我们目前普遍使用的 mysql 版本都是支持这一语法的。

          语法:

          # 定义预处理语句
          prepare stmt_name from preparable_stmt;
          # 执行预处理语句
          execute stmt_name [using @var_name [, @var_name] ...];
          # 删除(释放)定义
          {deallocate | drop} prepare stmt_name;

           1、利用字符串定义预处理 sql (直角三角形计算)

          mysql> prepare stmt1 from 'select sqrt(pow(?,2) + pow(?,2)) as hypotenuse';
          query ok, 0 rows affected (0.00 sec)
          statement prepared
          
          mysql> set @a = 3;
          query ok, 0 rows affected (0.00 sec)
          
          mysql> set @b = 4;                                                   
          query ok, 0 rows affected (0.00 sec)
          
          mysql> execute stmt1 using @a, @b;
          +------------+
          | hypotenuse |
          +------------+
          |          5 |
          +------------+
          1 row in set (0.00 sec)
          
          mysql> deallocate prepare stmt1;                                     
          query ok, 0 rows affected (0.00 sec)

           2、利用变量定义预处理 sql (直角三角形计算)

          mysql> set @s = 'select sqrt(pow(?,2) + pow(?,2)) as hypotenuse';
          query ok, 0 rows affected (0.00 sec)
          
          mysql> prepare stmt2 from @s;
          query ok, 0 rows affected (0.00 sec)
          statement prepared
          
          mysql> set @c = 6;
          query ok, 0 rows affected (0.00 sec)
          
          mysql> set @d = 8;
          query ok, 0 rows affected (0.00 sec)
          
          mysql> execute stmt2 using @c, @d;
          +------------+
          | hypotenuse |
          +------------+
          |         10 |
          +------------+
          1 row in set (0.00 sec)
          
          mysql> deallocate prepare stmt2;
          query ok, 0 rows affected (0.00 sec)

           3、解决无法传参问题

          我们知道,对于 limit 子句中的值,必须是常量,不得使用变量,也就是说不能使用:select * from table limit @skip, @numrows; 如此,就可以是用 prepare 语句解决此问题。

          mysql> set @skip = 100; set @numrows = 3;
          query ok, 0 rows affected (0.00 sec)
          
          query ok, 0 rows affected (0.00 sec)
          
          mysql> select * from t1 limit @skip, @numrows;
          error 1064 (42000): you have an error in your sql syntax; check the manual that corresponds to your mysql server version for the right syntax to use near '@skip, @numrows' at line 1
          
          mysql> prepare stmt3 from "select * from t1 limit ?, ?";
          query ok, 0 rows affected (0.00 sec)
          statement prepared
          
          mysql> execute stmt3 using @skip, @numrows;
          +-----+--------+
          | a   | filler |
          +-----+--------+
          | 100 | filler |
          | 101 | filler |
          | 102 | filler |
          +-----+--------+
          3 rows in set (0.00 sec)
          
          mysql> deallocate prepare stmt3;
          query ok, 0 rows affected (0.00 sec)

          如此一来,结合2中介绍的利用变量定义预处理 sql 也就基本解决了传参时语法报错问题了,类似的:用变量传参做表名时,mysql 会把变量名当做表名,这样既不是本意,也会是语法错误,在 sql server 的解决办法是利用字符串拼接穿插变量进行传参,再将整条 sql 语句作为变量,最后是用 sp_executesql 调用该拼接 sql 执行,而 prepared sql statement 可谓异曲同工之妙。

          mysql> set @table = 't2';
          query ok, 0 rows affected (0.00 sec)
          
          mysql> set @s = concat('select * from ', @table);
          query ok, 0 rows affected (0.00 sec)
          
          mysql> prepare stmt4 from @s;
          query ok, 0 rows affected (0.00 sec)
          statement prepared
          
          mysql> execute stmt4;
          +------+-------+-------+
          | id   | score | grade |
          +------+-------+-------+
          |    1 |    99 | a     |
          |    2 |    81 | b     |
          |    3 |    55 | d     |
          |    4 |    69 | c     |
          +------+-------+-------+
          4 rows in set (0.00 sec)
          
          mysql> drop prepare stmt4;
          query ok, 0 rows affected (0.00 sec)

          三、预处理 sql 使用注意点

          1、stmt_name 作为 preparable_stmt 的接收者,唯一标识,不区分大小写。

          2、preparable_stmt 语句中的 ? 是个占位符,所代表的是一个字符串,不需要将 ? 用引号包含起来。

          3、定义一个已存在的 stmt_name ,原有的将被立即释放,类似于变量的重新赋值。

          4、prepare stmt_name 的作用域是session级

          可以通过 max_prepared_stmt_count 变量来控制全局最大的存储的预处理语句。

          mysql> show variables like 'max_prepared%';
          +-------------------------+-------+
          | variable_name           | value |
          +-------------------------+-------+
          | max_prepared_stmt_count | 16382 |
          +-------------------------+-------+
          1 row in set (0.00 sec)

          预处理编译 sql 是占用资源的,所以在使用后注意及时使用 deallocate prepare 释放资源,这是一个好习惯。

          四、prepared statements优点

          1.安全

          prepared statements通过sql逻辑与数据的分离来增加安全,sql逻辑与数据的分离能防止普通类型的sql注入攻击(sql injection attack)。

          2.性能

          prepared statements只语法分析一次,你初始话prepared statements时,mysql将检查语法并准备语句的运行,当你执行query 多次时,这样就不会在有额外的负担了,如果,当运行query 很多次的时候(如:insert)这种预处理有很大的性能提高

          他使用binary protocol协议,这样更能提高效率。

          总结

          到此这篇关于mysql sql预处理(prepared)的文章就介绍到这了,更多相关mysql sql预处理(prepared)内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!

          (0)
          上一篇 2022年3月21日
          下一篇 2022年3月21日

          相关推荐