mysql statement 基本操作
概述
MySQL客户端/服务器协议提供了预处理语句。该功能采用了由mysql_stmt_init()初始化函数返回的MYSQL_STMT语句处理程序数据结构。对于多次执行的语句,预处理执行是一种有效的方式。首先对语句进行解析,为执行作好准备。接下来,在以后使用初始化函数返回的语句句柄执行一次或多次。
对于多次执行的语句,预处理执行比直接执行快,主要原因在于,仅对查询执行一次解析操作。在直接执行的情况下,每次执行语句时,均将进行查询。此外,由于每次执行预处理语句时仅需发送参数的数据,从而减少了网络通信量。
预处理语句的另一个优点是,它采用了二进制协议,从而使得客户端和服务器之间的数据传输更有效率。
下述语句可用作预处理语句:CREATE TABLE、DELETE、DO、INSERT、REPLACE、SELECT、SET、UPDATE、以及大多数SHOW语句。在MySQL 5.1中,不支持其他语句。
mysql statement基本操作接口
mysql_stmt_init()
-
描述
MYSQL_STMT *mysql_stmt_init(MYSQL *mysql)
创建MYSQL_STMT句柄。对于该句柄,应使用mysql_stmt_close(MYSQL_STMT *)释放。
-
返回值
成功时,返回指向MYSQL_STMT结构的指针。如果内存溢出,返回NULL。
-
错误
CR_OUT_OF_MEMORY 内存溢出
mysql_stmt_prepare()
-
描述
int mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned long length)
给定mysql_stmt_init()返回的语句句柄,准备字符串查询指向的SQL语句,并返回状态值。字符串长度应由“length”参量给出。字符串必须包含1条SQL语句。不应为语句添加终结用分号(‘;’)或\g。
通过将问号字符“?”嵌入到SQL字符串的恰当位置,应用程序可包含SQL语句中的一个或多个参数标记符。
标记符仅在SQL语句中的特定位置时才是合法的。例如,它可以在INSERT语句的VALUES()列表中(为行指定列值),或与WHERE子句中某列的比较部分(用以指定比较值)。但是,对于ID(例如表名或列名),不允许使用它们,不允许指定二进制操作符(如等于号“=”)的操作数。后一个限制是有必要的,原因在于,无法确定参数类型。一般而言,参数仅在DML(数据操作语言)语句中才是合法的,在DDL(数据定义语言)语句中不合法。
执行语句之前,必须使用mysql_stmt_bind_param(),将参数标记符与应用程序变量绑定在一起。
如果准备操作失败(即mysql_stmt_prepare()返回非0值),可通过调用mysql_stmt_error()获取错误消息。
-
返回值
如果成功处理了语句,返回0。如果出现错误,返回非0值。
-
错误
错误码 错误描述 CR_COMMANDS_OUT_OF_SYNC 以不恰当的顺序执行了命令 CR_OUT_OF_MEMORY 内存溢出 CR_SERVER_GONE_ERROR MySQL服务器不可用 CR_SERVER_LOST 查询过程中,与服务器的连接丢失 CR_UNKNOWN_ERROR 出现未知错误
mysql_stmt_bind_param()
-
描述
my_bool mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind)
mysql_stmt_bind_param()用于为SQL语句中的参数标记符绑定数据,以传递给mysql_stmt_prepare()。它使用MYSQL_BIND结构来提供数据。“bind”是MYSQL_BIND结构的某一数组的地址。按照客户端库的预期,对于查询中出现的每个“?”参数标记符,数组中均包含1个元素。
假定你准备了下述语句:
INSERT INTO mytbl VALUES(?,?,?)
绑定参数时,MYSQL_BIND结构的数组包含3个元素,并能声明如下:
MYSQL_BIND bind[3];
-
返回值
如果绑定成功,返回0。如果出现错误,返回非0值。
-
错误码
错误码 错误提示 CR_INVALID_BUFFER_USE 指明“bind”(绑定)是否将提供程序块中的长数据,以及缓冲类型是否为非字符串或二进制类型 CR_UNSUPPORTED_PARAM_TYPE 不支持该转换。或许buffer_type值是非法的,或不是所支持的类型之一 CR_OUT_OF_MEMORY 内存溢出 CR_UNKNOWN_ERROR 未知错误
mysql_stmt_bind_result()
-
描述
my_bool mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
mysql_stmt_bind_result()用于将结果集中的列与数据缓冲和长度缓冲关联(绑定)起来。当调用mysql_stmt_fetch()以获取数据时,MySQL客户端/服务器协议会将绑定列的数据置于指定的缓冲区内。
调用mysql_stmt_fetch()之前,必须将所有列绑定到缓冲。“bind”是MYSQL_BIND结构某一数组的地址。按照客户端库的预期,对于结果集中的每一列,数组应包含相应的元素。如果未将列绑定到MYSQL_BIND结构,mysql_stmt_fetch()将简单地忽略数据获取操作。缓冲区应足够大,足以容纳数据值,这是因为协议不返回成块的数据值。
可以在任何时候绑定或再绑定列,即使已部分检索了结果集后也同样。新的绑定将在下一次调用mysql_stmt_fetch()时起作用。假定某一应用程序绑定了结果集中的列,并调用了mysql_stmt_fetch()。客户端/服务器协议将返回绑定缓冲区中的数据。接下来,假定应用程序将多个列绑定到不同的缓冲。该协议不会将数据置于新绑定的缓冲区,直至下次调用mysql_stmt_fetch()为止。
-
返回值 (mysql_stmt_bind_param)
*int mysql_stmt_execute(MYSQL_STMT stmt)
-
描述
mysql_stmt_execute()执行与语句句柄相关的预处理查询。在该调用期间,将当前绑定的参数标记符的值发送到服务器,服务器用新提供的数据替换标记符。
如果语句是UPDATE、DELETE或INSERT,通过调用mysql_stmt_affected_rows(),可发现更改、删除或插入的总行数。如果这是诸如SELECT等能生成结果集的语句,调用任何其他能导致查询处理的函数之前,必须调用mysql_stmt_fetch()来获取数据。
对于生成结果集的语句,执行语句之前,可通过调用mysql_stmt_attr_set(),请求mysql_stmt_execute()为语句打开光标。如果多次执行某一语句,在打开新的光标前,mysql_stmt_execute()将关闭任何已打开的光标。
-
返回值及错误码
如果执行成功,返回0。如果出现错误,返回非0值。
错误码 错误描述 CR_COMMANDS_OUT_OF_SYNC 以不恰当的顺序执行了命令 CR_OUT_OF_MEMORY 内存溢出 CR_SERVER_GONE_ERROR MySQL服务器不可用 CR_SERVER_LOST 在查询过程中,与服务器的连接丢失 CR_UNKNOWN_ERROR 出现未知错误
*int mysql_stmt_fetch(MYSQL_STMT stmt)
-
描述
mysql_stmt_fetch()返回结果集中的下一行。仅能当结果集存在时调用它,也就是说,调用了能创建结果集的mysql_stmt_execute()之后,或当mysql_stmt_execute()对整个结果集即行缓冲处理后调用了mysql_stmt_store_result()。
使用mysql_stmt_bind_result()绑定的缓冲,mysql_stmt_fetch()返回行数据。对于当前列集合中的所有列,它将返回缓冲内的数据,并将长度返回到长度指针。
调用mysql_stmt_fetch()之前,应用程序必须绑定所有列。
参考文献
示例
#include <iostream>
#include <queue>
#include <winsock.h>
#include <mysql.h>
#pragma comment(lib,"wsock32.lib")
using namespace std;
const char* HOST = "127.0.0.1";
const char* USER = "root";
const char* PSW = "adminroot";
const char* DB = "sakila";
const int PORT = 3306;
struct ActorResult
{
short actor_id;
char first_name[64];
char last_name[64];
union
{
char last_update[24];
struct
{
int year;
int month;
int day;
int hour;
int min;
int sec;
};
};
};
int main()
{
MYSQL sqlHandler;
mysql_init(&sqlHandler);
//返回false则连接失败,返回true则连接成功
if (!(mysql_real_connect(&sqlHandler, HOST, USER, PSW, DB, PORT, NULL, 0)))
//中间分别是主机,用户名,密码,数据库名,端口号(可以写默认0或者3306等),可以先写成参数再传进去
{
printf("Error connecting to database:%s\n", mysql_error(&sqlHandler));
return 0;
}
printf("Connected...\n");
mysql_set_character_set(&sqlHandler, "utf8");
MYSQL_BIND sqlParam[10];
MYSQL_BIND sqlResult[10];
MYSQL_STMT* pStmtHandler = mysql_stmt_init(&sqlHandler);
const char* sql = "select * from actor where actor_id < ?";
mysql_stmt_prepare(pStmtHandler, sql, (unsigned long)strlen(sql));
cout<< pStmtHandler->field_count << endl;
pStmtHandler->param_count;
//绑定参数
int actor_id = 10;
memset(sqlParam, 0, sizeof(sqlParam));
sqlParam[0].buffer_type = MYSQL_TYPE_SHORT;
sqlParam[0].buffer = &actor_id;
mysql_stmt_bind_param(pStmtHandler, sqlParam);
//绑定结果
ActorResult actorResult;
memset(&actorResult, 0, sizeof(actorResult));
memset(sqlResult, 0, sizeof(sqlResult));
sqlResult[0].buffer_type = MYSQL_TYPE_SHORT;
sqlResult[0].buffer = &(actorResult.actor_id);
sqlResult[1].buffer_type = MYSQL_TYPE_VAR_STRING;
sqlResult[1].buffer = actorResult.first_name;
sqlResult[1].buffer_length = 64;
sqlResult[2].buffer_type = MYSQL_TYPE_VAR_STRING;
sqlResult[2].buffer = actorResult.last_name;
sqlResult[2].buffer_length = 64;
sqlResult[3].buffer_type = MYSQL_TYPE_TIMESTAMP;
sqlResult[3].buffer = actorResult.last_update;
int ret = mysql_stmt_bind_result(pStmtHandler, sqlResult);
if (ret != 0)
{
int error = mysql_stmt_errno(pStmtHandler);
}
//执行sql
mysql_stmt_execute(pStmtHandler);
mysql_stmt_store_result(pStmtHandler);
int rows = mysql_stmt_num_rows(pStmtHandler);
while ((ret = mysql_stmt_fetch(pStmtHandler)) == 0)
{
cout << actorResult.actor_id <<endl;
}
cout<< ret <<endl;
getchar();
return 0;
}