Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  SQL Statements  /  Prepared Statements

15.5 预备语句

MySQL 8.3 提供了服务器端预备语句的支持。该支持利用了高效的客户端/服务器二进制协议。使用预备语句带有参数值占位符具有以下优点:

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

  • 保护against 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 语句”

在使用 CALL 语句时,使用 PREPAREEXECUTE,从 MySQL 8.3 开始支持 OUTINOUT 参数的占位符。见 第 15.2.1 节,“CALL 语句”,以获取示例和早期版本的解决方案。无论版本如何,均可以使用占位符来指定 IN 参数。

预备语句的 SQL 语法不能嵌套使用。也就是说,传递给 PREPARE 的语句不能本身是一个 PREPAREEXECUTE释放预备语句 语句。

预备语句的 SQL 语法与使用预备语句 API 调用是不同的。例如,您不能使用 mysql_stmt_prepare() C API 函数来准备 PREPAREEXECUTE释放预备语句 语句。

在存储过程中可以使用预备语句的 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 语句”