文档首页
MySQL 8.4 参考手册
相关文档 下载本手册
PDF(US Ltr) - 39.9Mb
PDF(A4) - 40.0Mb
手册页(TGZ) - 258.5Kb
手册页(Zip) - 365.5Kb
Info(Gzip) - 4.0Mb
Info(Zip) - 4.0Mb


MySQL 8.4 参考手册  /  SQL 语句  /  预处理语句

15.5 预处理语句

MySQL 8.4 提供对服务器端预处理语句的支持。此支持利用了高效的客户端/服务器二进制协议。使用带有参数值占位符的预处理语句具有以下优势

  • 每次执行语句时解析语句的开销更少。通常,数据库应用程序会处理大量几乎相同的语句,只是在诸如查询和删除的 WHERE 子句、更新的 SET 子句以及插入的 VALUES 子句中对字面量或变量值进行了更改。

  • 防止 SQL 注入攻击。参数值可以包含未转义的 SQL 引号和分隔符字符。

以下部分概述了预处理语句的特点

应用程序中的预处理语句

您可以通过客户端编程接口使用服务器端准备好的语句,包括用于 C 程序的 MySQL C API 客户端库,用于 Java 程序的 MySQL Connector/J 以及用于使用 .NET 技术的程序的 MySQL Connector/NET。例如,C API 提供了一组构成其准备好的语句 API 的函数调用。请参见 C API 准备好的语句接口。其他语言接口可以通过链接到 C 客户端库来提供对使用二进制协议的准备好的语句的支持,例如,在 PHP 5.0 及更高版本中可用的 mysqli 扩展

SQL 脚本中的准备好的语句

提供了一种替代的 SQL 接口来使用准备好的语句。此接口不如使用二进制协议通过准备好的语句 API 高效,但不需要编程,因为它可以直接在 SQL 级别使用。

  • 当您无法使用任何编程接口时,可以使用它。

  • 您可以从任何可以将 SQL 语句发送到服务器以执行的程序中使用它,例如 mysql 客户端程序。

  • 即使客户端使用的是旧版本的客户端库,也可以使用它。

准备好的语句的 SQL 语法旨在用于以下情况

  • 在对应用程序进行编码之前,测试准备好的语句在您的应用程序中的工作方式。

  • 当您无权访问支持准备好的语句的编程 API 时,使用准备好的语句。

  • 以交互方式排查与准备好的语句相关的应用程序问题。

  • 创建一个测试用例来重现与准备好的语句相关的问题,以便您可以提交错误报告。

PREPARE、EXECUTE 和 DEALLOCATE PREPARE 语句

准备好的语句的 SQL 语法基于三个 SQL 语句

以下示例展示了两种等效的方式,用于准备一个计算直角三角形的斜边长度的语句(给定两条边的长度)。

第一个示例展示了如何使用字符串文字来提供语句文本,从而创建准备好的语句

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;

第二个示例类似,但它将语句文本作为用户变量提供

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;

这是一个额外的示例,它展示了如何在运行时选择要执行查询的表,方法是将表的名称存储为用户变量

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;

准备好的语句特定于创建它的会话。如果您终止一个会话,而没有释放以前准备好的语句,服务器会自动释放它。

准备好的语句对于会话也是全局的。如果您在存储过程中创建了准备好的语句,它在存储过程结束时不会被释放。

为防止同时创建过多的准备好的语句,请设置 max_prepared_stmt_count 系统变量。要禁止使用准备好的语句,请将该值设置为 0。

准备好的语句中允许的 SQL 语法

以下 SQL 语句可用作准备好的语句

ALTER TABLE
ALTER USER
ANALYZE TABLE
CACHE INDEX
CALL
CHANGE MASTER
CHECKSUM {TABLE | TABLES}
COMMIT
{CREATE | DROP} INDEX
{CREATE | RENAME | DROP} DATABASE
{CREATE | DROP} TABLE
{CREATE | RENAME | DROP} USER
{CREATE | DROP} VIEW
DELETE
DO
FLUSH {TABLE | TABLES | TABLES WITH READ LOCK | HOSTS | PRIVILEGES
  | LOGS | STATUS | MASTER | SLAVE | USER_RESOURCES}
GRANT
INSERT
INSTALL PLUGIN
KILL
LOAD INDEX INTO CACHE
OPTIMIZE TABLE
RENAME TABLE
REPAIR TABLE
REPLACE
RESET {MASTER | SLAVE}
REVOKE
SELECT
SET
SHOW BINLOG EVENTS
SHOW CREATE {PROCEDURE | FUNCTION | EVENT | TABLE | VIEW}
SHOW {MASTER | BINARY} LOGS
SHOW {MASTER | SLAVE} STATUS
SLAVE {START | STOP}
TRUNCATE TABLE
UNINSTALL PLUGIN
UPDATE

其他语句不受支持。

为了符合 SQL 标准(该标准指出诊断语句不可准备),MySQL 不支持以下内容作为准备好的语句

  • SHOW WARNINGSSHOW COUNT(*) WARNINGS

  • SHOW ERRORSSHOW COUNT(*) ERRORS

  • 包含对 warning_counterror_count 系统变量的任何引用的语句。

通常,SQL 准备好的语句中不允许的语句在存储程序中也不允许。例外情况在 第 27.8 节,“存储程序的限制” 中指出。

对准备好的语句引用的表或视图的元数据更改会被检测到,并会在下次执行语句时自动重新准备语句。有关更多信息,请参见 第 10.10.3 节,“准备好的语句和存储程序的缓存”

在使用准备好的语句时,可以使用占位符作为 LIMIT 子句的参数。请参见 第 15.2.13 节,“SELECT 语句”

在与 PREPAREEXECUTE 一起使用的准备好的 CALL 语句中,从 MySQL 8.4 开始,支持对 OUTINOUT 参数使用占位符。请参见 第 15.2.1 节,“CALL 语句”,以获取早期版本的示例和解决方法。无论版本如何,都可以对 IN 参数使用占位符。

准备好的语句的 SQL 语法不能以嵌套的方式使用。也就是说,传递给 PREPARE 的语句本身不能是 PREPAREEXECUTEDEALLOCATE PREPARE 语句。

准备好的语句的 SQL 语法不同于使用准备好的语句 API 调用。例如,您不能使用 mysql_stmt_prepare() C API 函数来准备 PREPAREEXECUTEDEALLOCATE PREPARE 语句。

准备好的语句的 SQL 语法可以在存储过程中使用,但不能在存储函数或触发器中使用。但是,游标不能用于使用 PREPAREEXECUTE 准备和执行的动态语句。游标的语句在游标创建时进行检查,因此该语句不能是动态的。

准备好的语句的 SQL 语法不支持多语句(即,用 ; 字符分隔的单个字符串中的多个语句)。

要编写使用 CALL SQL 语句执行包含准备好的语句的存储过程的 C 程序,必须启用 CLIENT_MULTI_RESULTS 标志。这是因为每个 CALL 都返回一个结果来指示调用状态,此外还有可能由过程内执行的语句返回的任何结果集。

CLIENT_MULTI_RESULTS 可以在您调用 mysql_real_connect() 时启用,方法是显式传递 CLIENT_MULTI_RESULTS 标志本身,或者隐式传递 CLIENT_MULTI_STATEMENTS(它还启用 CLIENT_MULTI_RESULTS)。有关更多信息,请参见 第 15.2.1 节,“CALL 语句”