分类: Mysql/postgreSQL
2010-01-06 16:23:39
Prepared statement(翻成 预编 ?)是一种不同于直接执行(查询)的方式。直接执行方式中,每次查询都会解析一次查询语句,再执行。而预编模式则可以将解析的结果保存,再执行。这样对于同一查询反复执行的情景,只需执行一次解析,后面反复执行这个解析的结果就成了,只需每次执行时给定语句中的参数。从而实现效率的提高。
注意的是,并不是所有环境下预编都会比直接执行的效率高。
支持预编模式的语句大致有:CALL, CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET, UPDATE。
基本步骤:
a) mysql_stmt_init(), 初始化
b) mysql_stmt_prepare, 预编译语句
loop begin
c) mysql_stmt_bind_param(),给定每次查询的参数
d) mysql_stmt_execute(), 执行
e) mysql_stmt_bind_result(), 绑定结果输出缓冲
f) mysql_stmt_store_result(), 获取全部结果
loop begin
g)mysql_stmt_fetch(),取一行结果
loop end
loop end
h) mysql_stmt_close(),释放
一个查询对应一个prepared statement,调用mysql_stmt_init后会得到一个handle,使用完后应该close。stmt handle与 数据库连接(connection)的关系是多对一的关系。
1) MYSQL_STMT
stmt handle的机构,代表一个prepared语句。mysql_stmt_init()生成,mysql_stmt_close()注销。
2)MYSQL_BIND
用于给定输入的语句参数,和输出的结果。使用前应当用0初始化。语句中参数使用'?'占位。
其中几个重要的域
field |
input(bind param) |
output (bind result) |
|
值的类型 |
期望接收的值类型 |
|
参数的内容 |
保存结果的buffer |
|
*buffer的长度 |
*buffer能容纳的最大长度 |
|
实际长度。数字类型的值,此域忽略。 |
实际长度。数字类型的值,此域忽略。 |
|
是否这个域传入NULL值 |
域值是否NULL |
|
是否unsigned |
是否unsigned |
|
|
对于truncate有特别的用途。 |
3)MYSQL_TIME
用于表示DATE,TIME,DATETIME和TIMESTAMP。
id |
func |
Description |
1 |
mysql_stmt_init() |
分配stmt handle结构内存,初始化 |
2 |
mysql_stmt_close() |
释放stmt handle |
3 |
mysql_stmt_prepare() |
预编查询/语句 |
4 |
mysql_stmt_bind_param() |
绑定入口参数 |
5 |
mysql_stmt_bind_result() |
绑定出口参数 |
6 |
mysql_stmt_execute() |
执行 |
7 |
mysql_stmt_store_result() |
取回所有结果 |
8 |
mysql_stmt_fetch() |
取一行结果。 |
预备条件:
server上的账户 root:passwd@localhost:3306, 数据库是world, 其中的表city结构如下
mysql> desc
city;
+-------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+----------+------+-----+---------+----------------+
| ID | int(11) | NO
| PRI | NULL | auto_increment |
| Name | char(35) | NO |
| | |
| CountryCode |
char(3) | NO |
| | |
| District | char(20) | NO |
| | |
|
Population | int(11) | NO
| | 0 | |
+-------------+----------+------+-----+---------+----------------+
5 rows in set
(0.00 sec)
程序如下
// mysqlTest.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "mysql.h"
#define MYSQL_PORT 3306
#define MYSQL_HOST "localhost"
#define MYSQL_USER "root"
#define MYSQL_PASSWD "passwd"
#define MYSQL_DB "world"
#define MYSQL_NAME_LEN 35
#define MYSQL_SELECTSTATEMENT "select id, name from city where id=?"
int _tmain(int argc, _TCHAR* argv[])
{
int
result;
MYSQL mySQLHandler;
MYSQL_STMT *mySQLStmt;
MYSQL_BIND mySQLBindInput;
MYSQL_BIND mySQLBindOutput[2];
int
cityId=0;
my_bool isNullInput = FALSE;
my_bool isNullOutput[2];
my_bool isUnsigned = TRUE;
unsigned
long length[2];
my_bool err[2];
int
id;
char
name[MYSQL_NAME_LEN];
mysql_library_init(0,NULL,NULL);
mysql_init(&mySQLHandler);
printf("1.
inited ---------------\n");
if
(!mysql_real_connect(&mySQLHandler, MYSQL_HOST, MYSQL_USER, MYSQL_PASSWD,
MYSQL_DB,MYSQL_PORT, NULL, 0))
{
printf( "Error connecting to database: %s\n",mysql_error(&mySQLHandler));
exit(1);
}
printf("2.
connected ---------------\n");
mySQLStmt =
mysql_stmt_init(&mySQLHandler);
if
(!mySQLStmt)
{
printf( "stmt init err\n");
exit(1);
}
printf(".
stmt init ---------------\n");
result =
mysql_stmt_prepare(mySQLStmt, MYSQL_SELECTSTATEMENT,
strlen(MYSQL_SELECTSTATEMENT));
if
(result)
{
printf( "Error stmt prepare: %s\n",mysql_error(&mySQLHandler));
exit(1);
}
printf(".
stmt prepare ---------------\n");
while(1)
{
cityId++;
memset(&mySQLBindInput,
0, sizeof(MYSQL_BIND));
mySQLBindInput.buffer_type =
MYSQL_TYPE_LONG;
mySQLBindInput.buffer =
&cityId;
// mySQLBindInput.buffer_length
= sizeof(cityId); // this is ignored by mysql because the type is numeric.
// mySQLBindInput.length
= 0; // this is ignored by mysql because the type is numeric.
mySQLBindInput.is_null = 0;
result =
mysql_stmt_bind_param(mySQLStmt, &mySQLBindInput) ;
if
(result)
{
printf( "Error bind param: %s\n",mysql_error(&mySQLHandler));
exit(1);
}
// printf(".
bind param %d ---------------\n", cityId);
result = mysql_stmt_execute(mySQLStmt);
if
(result)
{
printf( "Error execute: %s\n",mysql_error(&mySQLHandler));
exit(1);
}
// printf(".
Execute ---------------\n");
memset(&mySQLBindOutput[0],
0, sizeof(MYSQL_BIND));
memset(&mySQLBindOutput[1],
0, sizeof(MYSQL_BIND));
mySQLBindOutput[0].buffer_type
=MYSQL_TYPE_LONG;
mySQLBindOutput[0].buffer =
&id;
mySQLBindOutput[0].buffer_length
= sizeof(id); // this
is ignored by mysql because the type is numeric.
mySQLBindOutput[0].length
= &length[0];
mySQLBindOutput[0].is_null =
&isNullOutput[0];
mySQLBindOutput[0].error =
&err[0];
mySQLBindOutput[1].buffer_type
=MYSQL_TYPE_STRING;
mySQLBindOutput[1].buffer =
&name;
mySQLBindOutput[1].buffer_length
= MYSQL_NAME_LEN; // this is ignored by mysql because
the type is numeric.
mySQLBindOutput[1].length
= &length[1]; // this is ignored by mysql because the type is numeric.
mySQLBindOutput[1].is_null =
&isNullOutput[1];
mySQLBindOutput[1].error =
&err[1];
result =
mysql_stmt_bind_result(mySQLStmt, mySQLBindOutput);
if
(result)
{
printf( "Error bind result: %s\n",mysql_error(&mySQLHandler));
exit(1);
}
// printf(".
bind result ---------------\n");
result =
mysql_stmt_store_result(mySQLStmt);
if
(result)
{
printf( "Error store result: %s\n",mysql_error(&mySQLHandler));
exit(1);
}
// printf(".
store result ---------------\n");
// printf(".
fetching result ---------------\n");
if(mysql_stmt_num_rows(mySQLStmt)==0)
break;
while(!mysql_stmt_fetch(mySQLStmt))
{
printf("id= %d, name= %s \n",
isNullOutput[0]?0:id, isNullOutput[1]?0:name);
}
}
printf(".
fetch result over ---------------\n");
mysql_stmt_close(mySQLStmt);
printf(".
stmt close ---------------\n");
mysql_close(&mySQLHandler);
printf("6.close
mysql ---------------\n");
mysql_library_end();
return
0;
}