tencent cloud

TDSQL Boundless

产品动态
产品简介
产品概述
应用场景
产品架构
实例类型
兼容性说明
使用规范建议
自研内核
内核概述
内核版本更新动态
功能类特性
性能类特性
产品计费
计费概述
购买方式
价格详情
续费说明
欠费说明
退费说明
快速入门
创建实例
连接实例
用户指南
数据迁移
数据同步/订阅
实例管理
参数配置
账号管理
安全组
备份与恢复
数据库审计
标签管理
实践教程
Online DDL 的技术演进与使用实践
锁机制解析与问题排查实践
数据智能调度及相关性能优化实践
TDSQL Boundless 选型指南与实践教程
开发指南
开发指南(MySQL 兼容模式)
开发指南(HBase 兼容模式)
性能调优
性能调优概述
SQL 调优
DDL 调优
性能白皮书
性能概述
TPC-C 测试
Sysbench 测试
API 文档
History
Introduction
API Category
Making API Requests
Instance APIs
Security Group APIs
Task APIs
Backup APIs
Rollback APIs
Parameter APIs
Database APIs
Data Types
Error Codes
通用参考
系统原理
SQL 参考
数据库参数说明
TPC-H 基准测试数据模型参考
错误码信息
安全与合规
常见问题
服务协议
服务等级协议
服务条款
隐私政策
数据处理和安全协议
联系我们
词汇表

预处理语句

PDF
聚焦模式
字号
最后更新时间: 2026-03-30 09:36:42
本文介绍 TDSQL Boundless 中预处理语句 (Prepared Statement) 的概念、SQL 语法和使用方法。预处理语句通过将 SQL 语句模板化,实现语句与参数的分离,能够有效提升查询性能并防止 SQL 注入攻击。

预处理语句概述

预处理语句是一种将多个仅有参数不同的 SQL 语句进行模板化的技术。它将 SQL 语句的结构与实际参数分离,先由数据库服务端对 SQL 模板进行解析和编译,后续执行时只需传递参数即可。
TDSQL Boundless 兼容 MySQL 8.0 协议,完整支持预处理语句功能。预处理语句具有以下优势:
提升安全性:参数与 SQL 语句分离传输,从根本上避免 SQL 注入攻击风险。
提升性能:SQL 语句仅需在首次执行时解析和编译一次,后续执行同一语句时只需传递不同的参数值,节省了重复解析的开销。
降低网络开销:执行阶段仅传输参数值,无需重复传输完整的 SQL 文本,减少了客户端与服务端之间的网络传输量。
在应用程序开发中,使用预处理语句执行 SQL 操作是推荐的最佳实践。

预处理语句的工作流程

预处理语句的使用分为三个阶段:
1. 预处理 (Prepare):客户端将包含占位符的 SQL 语句模板发送到服务端。服务端对该语句进行语法解析和编译,生成执行计划并缓存,然后返回一个语句标识符。
2. 执行 (Execute):客户端通过语句标识符引用已预处理的语句,并传递实际的参数值。服务端将参数值绑定到对应的占位符上,执行语句并返回结果。
3. 释放 (Deallocate):当预处理语句不再使用时,客户端发送释放指令,服务端回收该语句占用的资源。

SQL 语法

TDSQL Boundless 支持通过 SQL 语句直接管理预处理语句的生命周期,包括创建、执行和删除操作。

创建预处理语句

使用 PREPARE 语句创建一个预处理语句。SQL 模板中使用英文半角问号 ? 作为参数占位符。
语法格式
PREPARE stmt_name FROM preparable_stmt;
参数说明
参数
说明
stmt_name
预处理语句的名称,用于后续引用该语句。名称在当前会话中必须唯一,不区分大小写
preparable_stmt
SQL 语句模板,可以是一个字符串字面量或用户变量。使用 ? 作为参数占位符
示例
以下示例创建一个根据 id 查询员工信息的预处理语句:
PREPARE stmt_query FROM 'SELECT * FROM employees WHERE id = ?';
也可以通过用户变量传入 SQL 模板:
SET @sql = 'SELECT * FROM employees WHERE id = ?';
PREPARE stmt_query FROM @sql;
说明:
预处理语句的作用域为当前会话。当会话结束时,会话中定义的所有预处理语句会自动释放。

执行预处理语句

使用 EXECUTE 语句执行已创建的预处理语句,并通过 USING 子句传递参数值。参数值必须通过用户变量传递。
语法格式
EXECUTE stmt_name [USING @var_name [, @var_name] ...];
参数说明
参数
说明
stmt_name
要执行的预处理语句名称,必须是已通过 PREPARE 创建的语句
@var_name
用户变量,用于向预处理语句传递参数值。变量的数量必须与 SQL 模板中 ? 占位符的数量一致
示例
执行上述创建的预处理语句,查询 id 为1的员工信息:
SET @id = 1;
EXECUTE stmt_query USING @id;
执行结果示例如下:
+----+----------+------------+--------+
| id | name | department | salary |
+----+----------+------------+--------+
| 1 | Zhang San| R&D | 15000 |
+----+----------+------------+--------+
1 row in set (0.00 sec)
传递不同的参数值即可重复执行同一条预处理语句:
SET @id = 2;
EXECUTE stmt_query USING @id;

删除预处理语句

使用 DEALLOCATE PREPARE 语句释放已创建的预处理语句,回收服务端资源。
语法格式
{DEALLOCATE | DROP} PREPARE stmt_name;
参数说明
参数
说明
stmt_name
要释放的预处理语句名称
示例
DEALLOCATE PREPARE stmt_query;
注意:
如果在未释放预处理语句的情况下断开会话连接,服务端会自动释放该会话中的所有预处理语句。但在长连接或连接池场景下,建议在预处理语句使用完毕后主动调用 DEALLOCATE PREPARE 释放资源,避免占用服务端内存。

使用示例

以下通过完整示例展示预处理语句在查询和数据操作场景中的用法。

查询示例

以下示例展示如何使用预处理语句查询 books 表中指定 id 的书籍信息。
1. 创建预处理语句:
PREPARE stmt_select_book FROM 'SELECT * FROM books WHERE id = ?';
2. 设置参数并执行查询:
SET @book_id = 1;
EXECUTE stmt_select_book USING @book_id;
3. 使用不同参数再次执行:
SET @book_id = 5;
EXECUTE stmt_select_book USING @book_id;
4. 释放预处理语句:
DEALLOCATE PREPARE stmt_select_book;

插入示例

以下示例展示如何使用预处理语句向 books 表中插入一条数据。
1. 创建预处理语句:
PREPARE stmt_insert_book FROM 'INSERT INTO books (title, type, stock, price, published_at) VALUES (?, ?, ?, ?, ?)';
2. 设置参数并执行插入:
SET @title = 'TDSQL Boundless 实战指南';
SET @type = 'Technology';
SET @stock = 100;
SET @price = 89.00;
SET @published_at = '2026-01-01';
EXECUTE stmt_insert_book USING @title, @type, @stock, @price, @published_at;
3. 释放预处理语句:
DEALLOCATE PREPARE stmt_insert_book;

更新示例

以下示例展示如何使用预处理语句更新 books 表中指定书籍的库存。
1. 创建预处理语句:
PREPARE stmt_update_stock FROM 'UPDATE books SET stock = ? WHERE id = ?';
2. 设置参数并执行更新:
SET @new_stock = 200;
SET @book_id = 1;
EXECUTE stmt_update_stock USING @new_stock, @book_id;
3. 释放预处理语句:
DEALLOCATE PREPARE stmt_update_stock;

删除示例

以下示例展示如何使用预处理语句删除 books 表中指定 id 的书籍记录。
1. 创建预处理语句:
PREPARE stmt_delete_book FROM 'DELETE FROM books WHERE id = ?';
2. 设置参数并执行删除:
SET @book_id = 10;
EXECUTE stmt_delete_book USING @book_id;
3. 释放预处理语句:
DEALLOCATE PREPARE stmt_delete_book;

动态 SQL 示例

预处理语句支持通过用户变量传入动态构建的 SQL 字符串,适用于需要在运行时决定 SQL 内容的场景。
以下示例展示如何动态检测当前数据库是否支持某个存储引擎变量:
-- 动态构造查询语句
SET @query_str = 'SELECT COUNT(*) INTO @result FROM performance_schema.session_variables WHERE VARIABLE_NAME = ?';
PREPARE stmt_check FROM @query_str;

-- 设置参数并执行
SET @var_name = 'rocksdb_bulk_load';
EXECUTE stmt_check USING @var_name;

-- 查看结果
SELECT @result;

-- 释放语句
DEALLOCATE PREPARE stmt_check;
说明:
mysqldump 工具在导出数据时,即使用了类似的 PREPARE...FROM @variable 方式动态构造 SQL 语句,用于检测目标服务器是否支持特定存储引擎功能。

支持的 SQL 语句类型

在 TDSQL Boundless 中,预处理语句支持以下类型的 SQL 语句:
数据操作语句
SELECT
INSERT
UPDATE
DELETE
REPLACE
CALL
DO
数据定义语句
CREATE DATABASECREATE TABLECREATE TEMPORARY TABLECREATE INDEXCREATE USER
DROP DATABASEDROP TABLEDROP TEMPORARY TABLEDROP INDEXDROP USERDROP VIEW
ALTER USER
RENAME TABLERENAME USER
TRUNCATE TABLE
数据库管理语句
ANALYZE TABLECHECKSUM TABLEOPTIMIZE TABLEREPAIR TABLE
GRANTREVOKE ALL PRIVILEGES
SHOW CREATE TABLESHOW CREATE PROCEDURESHOW CREATE FUNCTIONSHOW CREATE VIEWSHOW CREATE EVENT
SHOW BINLOG EVENTSSHOW MASTER STATUSSHOW BINARY LOGSSHOW SLAVE STATUS
INSTALL PLUGINUNINSTALL PLUGIN
KILL
COMMIT
SET OPTION
RESET MASTERRESET SLAVE
SLAVE STARTSLAVE STOP
说明:
不在上述列表中的 SQL 语句(例如 LOAD DATA INFILEUSEBEGIN 等)不支持通过预处理语句执行。

客户端编程接口

除 SQL 语法外,应用程序还可以通过 MySQL 客户端编程接口 (C API) 使用预处理语句功能。C API 使用 MySQL 二进制协议与服务端通信,相比文本协议具有更高的传输效率。

C API 调用流程

以下是 C API 中预处理语句的典型调用流程:
1. 使用 mysql_stmt_init() 初始化预处理语句句柄。
2. 使用 mysql_stmt_prepare() 将 SQL 模板发送到服务端进行预处理。
3. 使用 mysql_stmt_bind_param() 绑定参数值。
4. 使用 mysql_stmt_execute() 执行预处理语句。
5. 使用 mysql_stmt_bind_result()mysql_stmt_fetch() 获取查询结果(仅查询语句需要)。
6. 使用 mysql_stmt_close() 关闭语句句柄,释放资源。
以下是主要 API 函数的说明:
函数
说明
mysql_stmt_init()
初始化一个 MYSQL_STMT 句柄,用于后续的预处理操作
mysql_stmt_prepare()
将 SQL 语句模板发送到服务端进行解析和编译
mysql_stmt_bind_param()
将应用程序中的变量绑定到 SQL 模板中的 ? 占位符
mysql_stmt_execute()
执行已预处理的语句
mysql_stmt_store_result()
将完整的结果集从服务端读取到客户端缓存
mysql_stmt_result_metadata()
获取预处理语句返回结果的元数据信息(列名、类型等)
mysql_stmt_fetch()
逐行获取结果集数据
mysql_stmt_close()
关闭预处理语句句柄,释放客户端和服务端的相关资源
mysql_stmt_errno()
返回最近一次预处理语句操作的错误码
mysql_stmt_error()
返回最近一次预处理语句操作的错误信息
mysql_stmt_attr_set()
设置语句属性,例如游标类型 CURSOR_TYPE_READ_ONLY
mysql_stmt_next_result()
用于处理多结果集场景,获取下一个结果集

游标模式

C API 支持在预处理语句中使用服务端游标。通过设置语句属性 STMT_ATTR_CURSOR_TYPECURSOR_TYPE_READ_ONLY,可以启用只读游标模式。在该模式下,结果集不会一次性加载到客户端内存,而是按需逐行获取,适用于处理大数据量的查询场景。

编程语言驱动

各主流编程语言的 MySQL 驱动均封装了预处理语句功能,开发者无需直接调用 C API。以下为各语言中预处理语句的常用接口:
编程语言
驱动或框架
预处理语句接口
Java
JDBC
java.sql.PreparedStatement
Python
MySQL Connector/Python
cursor.execute(sql, params)
Go
go-sql-driver/mysql
db.Prepare() + stmt.Exec()
PHP
PDO
PDO::prepare() + PDOStatement::execute()
Node.js
mysql2
connection.execute(sql, values)
C/C++
MySQL C API
mysql_stmt_prepare() + mysql_stmt_execute()
说明:
TDSQL Boundless 兼容 MySQL 8.0 协议,标准的 MySQL 客户端驱动均可直接使用,无需修改。

JDBC 连接最佳实践

在使用 Java JDBC 连接 TDSQL Boundless 时,建议配置以下参数以获得最佳的预处理语句性能。
参数
推荐值
说明
useServerPrepStmts
true
启用服务端预处理语句。默认情况下 JDBC 使用客户端模拟预处理,设置为 true 后使用服务端预处理,可提升多次执行相同语句的性能
cachePrepStmts
true
启用客户端预处理语句缓存。避免每次使用时重复创建预处理语句
prepStmtCacheSqlLimit
2048
单条预处理语句的最大 SQL 长度(单位:字节)。默认值为256,对于复杂 SQL 语句可能不足,建议调大
prepStmtCacheSize
256
客户端缓存的预处理语句最大数量。默认值为25,建议根据应用实际使用的 SQL 语句数量调整
推荐的 JDBC 连接字符串示例
jdbc:mysql://<host>:<port>/<database>?useServerPrepStmts=true&cachePrepStmts=true&prepStmtCacheSqlLimit=2048&prepStmtCacheSize=256&rewriteBatchedStatements=true&allowMultiQueries=true
<host><port><database> 替换为 TDSQL Boundless 实例的实际连接信息。

审计与监控

TDSQL Boundless 的审计日志插件会记录预处理语句的执行事件。在审计日志中,预处理语句的操作会生成以下类型的事件记录:
事件类型
说明
Prepare
记录预处理语句的创建操作,包含 SQL 模板文本
Execute
记录预处理语句的执行操作,包含实际参数值
Query
记录通过文本协议执行的 PREPAREEXECUTEDEALLOCATE PREPARE 语句
审计日志中每条事件记录包含 COMMAND_CLASSCONNECTION_IDSTATUSSQLTEXT 等字段,可用于安全审计和执行分析。

预处理语句最佳实践

以下是使用预处理语句的推荐实践:
始终使用参数化查询:将所有外部输入通过参数占位符 ? 传递,避免将用户输入直接拼接到 SQL 字符串中,从根本上防止 SQL 注入攻击。
合理复用预处理语句:对于应用程序中频繁执行的 SQL 语句,创建一次预处理语句后多次执行,充分利用预处理带来的性能优势。
及时释放不再使用的语句:在长连接或连接池场景下,使用完毕后及时调用 DEALLOCATE PREPARE 释放预处理语句,避免占用服务端内存资源。
启用服务端预处理:在 JDBC 连接中将 useServerPrepStmts 设置为 true,使用服务端预处理而非客户端模拟,获得更高的执行效率。
配置客户端缓存:启用 cachePrepStmts 并合理设置 prepStmtCacheSizeprepStmtCacheSqlLimit,减少重复创建预处理语句的开销。

系统变量

系统变量 max_prepared_stmt_count 控制服务端允许同时存在的预处理语句总数。如果达到上限,新的 PREPARE 操作会返回错误。可通过 SHOW GLOBAL STATUS LIKE 'Prepared_stmt_count' 查看当前已创建的预处理语句数量。
变量
作用域
默认值
范围
说明
max_prepared_stmt_count
GLOBAL
16382
0 ~ 4194304
服务端允许同时存在的预处理语句全局总数(所有会话共计)。达到上限时新的 PREPARE 操作会返回 ERROR 1461 (42000): Can't create more than max_prepared_stmt_count statements

注意事项

在使用预处理语句时,需要注意以下事项:
预处理语句的作用域为当前会话。不同会话之间的预处理语句互相隔离,不能跨会话使用。
一条预处理语句中的参数占位符 ? 数量没有固定上限,但受 max_allowed_packet 系统变量的限制。
当客户端连接断开并重新连接后,之前创建的预处理语句会失效,需要重新执行 PREPARE 创建。
预处理语句中的 SQL 模板不支持包含多条语句(即不支持以分号 ; 分隔的多语句执行)。
使用 PREPARE ... FROM @variable 方式传入的 SQL 文本会在预处理时进行一次完整的语法解析,因此需确保用户变量中的 SQL 语句语法正确。
在分布式事务场景下,预处理语句与普通语句遵循相同的事务管理机制,可在事务内混合使用。

帮助和支持

本页内容是否解决了您的问题?

填写满意度调查问卷,共创更好文档体验。

文档反馈