MySQL 8.4 提供对服务器端预处理语句的支持。此支持利用了高效的客户端/服务器二进制协议。使用带有参数值占位符的预处理语句具有以下优势
以下部分概述了预处理语句的特点
应用程序中的预处理语句
您可以通过客户端编程接口使用服务器端准备好的语句,包括用于 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 语句
PREPARE
准备要执行的语句(请参见 第 15.5.1 节,“PREPARE 语句”)。EXECUTE
执行准备好的语句(请参见 第 15.5.2 节,“EXECUTE 语句”)。DEALLOCATE PREPARE
释放准备好的语句(请参见 第 15.5.3 节,“DEALLOCATE PREPARE 语句”)。
以下示例展示了两种等效的方式,用于准备一个计算直角三角形的斜边长度的语句(给定两条边的长度)。
第一个示例展示了如何使用字符串文字来提供语句文本,从而创建准备好的语句
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 WARNINGS
、SHOW COUNT(*) WARNINGS
SHOW ERRORS
、SHOW COUNT(*) ERRORS
包含对
warning_count
或error_count
系统变量的任何引用的语句。
通常,SQL 准备好的语句中不允许的语句在存储程序中也不允许。例外情况在 第 27.8 节,“存储程序的限制” 中指出。
对准备好的语句引用的表或视图的元数据更改会被检测到,并会在下次执行语句时自动重新准备语句。有关更多信息,请参见 第 10.10.3 节,“准备好的语句和存储程序的缓存”。
在使用准备好的语句时,可以使用占位符作为 LIMIT
子句的参数。请参见 第 15.2.13 节,“SELECT 语句”。
在与 PREPARE
和 EXECUTE
一起使用的准备好的 CALL
语句中,从 MySQL 8.4 开始,支持对 OUT
和 INOUT
参数使用占位符。请参见 第 15.2.1 节,“CALL 语句”,以获取早期版本的示例和解决方法。无论版本如何,都可以对 IN
参数使用占位符。
准备好的语句的 SQL 语法不能以嵌套的方式使用。也就是说,传递给 PREPARE
的语句本身不能是 PREPARE
、EXECUTE
或 DEALLOCATE PREPARE
语句。
准备好的语句的 SQL 语法不同于使用准备好的语句 API 调用。例如,您不能使用 mysql_stmt_prepare()
C API 函数来准备 PREPARE
、EXECUTE
或 DEALLOCATE PREPARE
语句。
准备好的语句的 SQL 语法可以在存储过程中使用,但不能在存储函数或触发器中使用。但是,游标不能用于使用 PREPARE
和 EXECUTE
准备和执行的动态语句。游标的语句在游标创建时进行检查,因此该语句不能是动态的。
准备好的语句的 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 语句”。