MySQL - C语言接口-预处理语句

版权声明:本文为CSDN博主「zhouxinfeng」的原创文章,原文链接:https://blog.csdn.net/zhouxinfeng/article/details/77891771

MySQL - C语言接口-预处理语句

对于多次执行的语句,预处理执行比直接执行快,主要原因在于,仅对查询执行一次解析操作。在直接执行的情况下,每次执行语句时,均将进行查询。此外,由于每次执行预处理语句仅需发送参数的数据,从而减少了网络通信量

A: select  *  from tablename
B: select *   from tablename

服务器一般处理方式:

A--->S--->A   B--->S--->B

服务器采取预处理机制

A--->S--->A   S--->B 减少一次解释执行
A:select * from tablename where id=?

B:select *  from tablename where name=?

预处理机制特点:

  1. 减少服务器负荷

  2. 提高服务器响应的速度

  3. 可以提供参数机制,让客户有更多查询方法

预处理机制数据类型

  • MYSQL_STMT 该结构表示预处理语句
  • MYSQL_BIND 该结构用于语句输入(发送给服务器的数据值)和输出(从服务器返回的结果值)
  1. 从客户传送数据到服务器
  2. 从服务器传输数据到客户

函数:

  1. MYSQL_STMT *mysql_stmt_init(MYSQL *mysql)
    创建MYSQL_STMT句柄。对于该句柄,应使用mysql_stmt_close(MYSQL_STMT *)释放

  2. int mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned long length)
    给定mysql_stmt_init()返回的语句句柄,准备字符串查询指向的SQL语句,并返回状态值。字符串长度应由“length”参量给出

  3. my_bool mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind)
    用于为SQL语句中的参数标记符绑定数据

  4. my_bool mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind)
    mysql_stmt_bind_result()用于将结果集中的列与数据缓冲和长度缓冲关联(绑定)起来

  5. int mysql_stmt_execute(MYSQL_STMT *stmt)
    mysql_stmt_execute()执行与语句句柄相关的预处理查询

  6. int mysql_stmt_store_result(MYSQL_STMT *stmt)
    以便后续的mysql_stmt_fetch()调用能返回缓冲数据

  7. int mysql_stmt_fetch(MYSQL_STMT *stmt)
    mysql_stmt_fetch()返回结果集中的下一行

  8. my_bool mysql_stmt_close(MYSQL_STMT *)
    关闭预处理语句

预处理机制步骤:

  1. MYSQL_STMT * st;

  2. 对处理的数据类型初始化 MYSQL_STMT * mysql_stmt_init(MYSQL*) st=mysql_stmt_init(MYSQL*);

  3. 将预处理句柄与具体sql语句绑定 int mysql_stmt_prepare(MYSQL_STMT * st,char * sql,int length);

    mysql_stmt_prepare(st,sql,strlen(str));

  4. mysql语句的参数

   select * from tablename where id=? and name=?

   给参数赋值

   MYSQL_BIND  para[n]   //1.n根据语句中参数确定(客户-->服务)     2.n根据语句中的字段数确定(服务-->客户)

   memset(para,0,sizeof(para));

   对参数操作

   para[0].buffer_type=MYSQL_TYPE_LONG   //设置参数的数据类型

   int id;

   para[0].buffer=&id;   //参数传值

 

   para[1].buffer_type=MYSQL_TYPE_STRING

   char str[20];

   para[1].buffer_length=sizeof(str);

   para[1].buffer=str;

  1. 预处理与参数绑定 mysql_stmt_bind_param(st,para);

  2. 执行 mysql_stmt_execute(st);

  3. 释放预处理机制所占的空间 mysql_stmt_close(MYSQL_STMT *) mysql_stmt_close(st);

示例1: 预处理语句 插入

/*

 * 客户端到服务端

 */

#include <stdio.h>
#include <mysql.h>
#include <string.h>

int main(void)
{
    MYSQL *conn = mysql_init(NULL);     //初始化服务器句柄
    /*登陆服务器*/
    if(!mysql_real_connect(conn, "localhost", "root", "", "test", 0, NULL, 0)) 
    {
        fprintf(stderr, "mysql_real_connect: %s\n", mysql_error(conn));
        return -1;
    }
    MYSQL_STMT *stmt = mysql_stmt_init(conn); //创建MYSQL_STMT句柄

    char *query = "insert into stu values(?, ?);";     // ?问号为占位符,表示一个参数;

    if(mysql_stmt_prepare(stmt, query, strlen(query)))		// stmt 绑定 SQL语句
    {
        fprintf(stderr, "mysql_stmt_prepare: %s\n", mysql_error(conn));
        return -1;
    }

    int id; char name[20];

    printf("id name: ");
    scanf("%d %s", &id, name);

    MYSQL_BIND params[2];				// 参数数组
    memset(params, 0, sizeof(params));

    params[0].buffer_type = MYSQL_TYPE_LONG;     // 参数数组设定类型和内容
    params[0].buffer = &id;						// 注意:int类型变量 需要用&符号,即,buff只接收指针类型

    params[1].buffer_type = MYSQL_TYPE_STRING;
    params[1].buffer = name;					// name已经是指针了
    params[1].buffer_length = strlen(name);		// 如果是字符串还需要明确长度
    
    mysql_stmt_bind_param(stmt, params);		// stmt 与参数数组的绑定

    mysql_stmt_execute(stmt);           		// 执行与语句句柄相关的预处理

    mysql_stmt_close(stmt);						// 关闭 预处理            

    mysql_close(conn);							// 关闭连接
    
    return 0;

}

示例2: 预处理语句读取

/*
 * 服务端到客户端
 */

#include <stdio.h>
#include <mysql.h>
#include <string.h>

int main(void)
{
    MYSQL *conn = mysql_init(NULL);     //初始化服务器句柄

    /*登陆服务器*/
    if(!mysql_real_connect(conn, "localhost", "root", "", "test", 0, NULL, 0))  
    {

        fprintf(stderr, "mysql_real_connect: %s\n", mysql_error(conn));
        return -1;
    }

    MYSQL_STMT *stmt = mysql_stmt_init(conn); //创建MYSQL_STMT句柄    预处理对象

    char *query = "select * from stu;";

    if(mysql_stmt_prepare(stmt, query, strlen(query)))			// 无参数的预处理
    {
        fprintf(stderr, "mysql_stmt_prepare: %s\n", mysql_error(conn));
        return -1;
    }
    
    int id; char name[20];

    //printf("id name: ");
    //scanf("%d %s", &id, name);

    MYSQL_BIND params[2];						// 读出内容为2个
    memset(params, 0, sizeof(params));

    params[0].buffer_type = MYSQL_TYPE_LONG;
    params[0].buffer = &id;

    params[1].buffer_type = MYSQL_TYPE_STRING;
    params[1].buffer = name;
    params[1].buffer_length = sizeof(name);

    //mysql_stmt_bind_param(stmt, params);

    mysql_stmt_bind_result(stmt, params); //用于将结果集中的列与数据缓冲和长度缓冲关联(绑定)起来

    mysql_stmt_execute(stmt);           //执行与语句句柄相关的预处理

    mysql_stmt_store_result(stmt);      //以便后续的mysql_stmt_fetch()调用能返回缓冲数据

    while(mysql_stmt_fetch(stmt) == 0) //返回结果集中的下一行
        printf("%d\t%s\n", id, name);
        
    mysql_stmt_close(stmt);             

    mysql_close(conn);
    
    return 0;

}

示例3:

/*

 * 客户端到服务端,再到客户端

 */

#include <stdio.h>
#include <mysql.h>
#include <string.h>

int main(void)
{
    MYSQL *conn = mysql_init(NULL);     //初始化服务器句柄
    /*登陆服务器*/
    if(!mysql_real_connect(conn, "localhost", "root", "", "test", 0, NULL, 0))  
    {
        fprintf(stderr, "mysql_real_connect: %s\n", mysql_error(conn));
        return -1;
    }
   
    MYSQL_STMT *stmt = mysql_stmt_init(conn); //创建MYSQL_STMT句柄

    char *query = "select * from stu where id=?;";

    if(mysql_stmt_prepare(stmt, query, strlen(query)))
    {
        fprintf(stderr, "mysql_stmt_prepare: %s\n", mysql_error(conn));
        return -1;
    }

    int id; char name[20];
    printf("id: ");
    scanf("%d",&id);

    MYSQL_BIND params[2];
    memset(params, 0, sizeof(params));

    params[0].buffer_type = MYSQL_TYPE_LONG;
    params[0].buffer = &id;
    
    params[1].buffer_type = MYSQL_TYPE_STRING;
    params[1].buffer = name;
    params[1].buffer_length = sizeof(name);

    mysql_stmt_bind_param(stmt, params);	// 绑定查询参数

    mysql_stmt_bind_result(stmt, params); 	// 绑定查询结果;用于将结果集中的列与数据缓冲和长度缓冲关联(绑定)起来

    mysql_stmt_execute(stmt);           //执行与语句句柄相关的预处理

    mysql_stmt_store_result(stmt);      //以便后续的mysql_stmt_fetch()调用能返回缓冲数据

    while(mysql_stmt_fetch(stmt) == 0) //返回结果集中的下一行
        printf("%d\t%s\n", id, name);

    mysql_stmt_close(stmt);             

    mysql_close(conn);

    return 0;

}

mysql stmt语法_mysql中SQL执行过程详解与用于预处理语句的SQL语法

mysql中SQL执行过程详解

在这里插入图片描述

客户端发送一条查询给服务器;

服务器先检查查询缓存,如果命中了缓存,则立刻返回存储在缓存中的结果。否则进入下一阶段。

服务器段进行SQL解析、预处理,在优化器生成对应的执行计划;

mysql根据优化器生成的执行计划,调用存储引擎的API来执行查询。

用于预处理语句的SQL语法

MySQL 5.1对服务器一方的预制语句提供支持。如果您使用合适的客户端编程界面,则这种支持可以发挥在MySQL 4.1中实施的高效客户端/服务器二进制协议的优势。候选界面包括MySQL C API客户端库(用于C程序)、MySQL Connector/J(用于Java程序)和MySQL Connector/NET。例如,C API可以提供一套能组成预制语句API的函数调用。请参见25.2.4节,“C API预处理语句”。其它语言界面可以对使用了二进制协议(通过在C客户端库中链接)的预制语句提供支持。有一个例子是PHP 5.0中的mysqli扩展。

对预制语句,还有一个SQL界面可以利用。与在整个预制语句API中使用二进制协议相比,本界面效率没有那么高,但是它不要求编程,因为在SQL层级,可以直接利用本界面:

· 当您无法利用编程界面时,您可以使用本界面。

· 有些程序允许您发送SQL语句到将被执行的服务器中,比如mysql客户端程序。您可以从这些程序中使用本界面。

· 即使客户端正在使用旧版本的客户端库,您也可以使用本界面。唯一的要求是,您能够连接到一个支持预制语句SQL语法的服务器上。

预制语句的SQL语法在以下情况下使用:

· 在编代码前,您想要测试预制语句在您的应用程序中运行得如何。或者也许一个应用程序在执行预制语句时有问题,您想要确定问题是什么。

· 您想要创建一个测试案例,该案例描述了您使用预制语句时出现的问题,以便您编制程序错误报告。

· 您需要使用预制语句,但是您无法使用支持预制语句的编程API。

预制语句的SQL语法基于三个SQL语句:

PREPARE stmt_name FROM preparable_stmt;

EXECUTE stmt_name [USING @var_name [, @var_name] …];

{DEALLOCATE | DROP} PREPARE stmt_name;

PREPARE语句用于预备一个语句,并赋予它名称stmt_name,借此在以后引用该语句。语句名称对案例不敏感。preparable_stmt可以是一个文字字符串,也可以是一个包含了语句文本的用户变量。该文本必须展现一个单一的SQL语句,而不是多个语句。使用本语句,‘?’字符可以被用于制作参数,以指示当您执行查询时,数据值在哪里与查询结合在一起。‘?’字符不应加引号,即使您想要把它们与字符串值结合在一起,也不要加引号。参数制作符只能被用于数据值应该出现的地方,不用于SQL关键词和标识符等。

如果带有此名称的预制语句已经存在,则在新的语言被预备以前,它会被隐含地解除分配。这意味着,如果新语句包含一个错误并且不能被预备,则会返回一个错误,并且不存在带有给定名称语句。

预制语句的范围是客户端会话。在此会话内,语句被创建。其它客户端看不到它。

在预备了一个语句后,您可使用一个EXECUTE语句(该语句引用了预制语句名称)来执行它。如果预制语句包含任何参数制造符,则您必须提供一个列举了用户变量(其中包含要与参数结合的值)的USING子句。参数值只能有用户变量提供,USING子句必须准确地指明用户变量。用户变量的数目与语句中的参数制造符的数量一样多。

您可以多次执行一个给定的预制语句,在每次执行前,把不同的变量传递给它,或把变量设置为不同的值。

要对一个预制语句解除分配,需使用DEALLOCATE PREPARE语句。尝试在解除分配后执行一个预制语句会导致错误。

如果您终止了一个客户端会话,同时没有对以前已预制的语句解除分配,则服务器会自动解除分配。

以下SQL语句可以被用在预制语句中:CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET, UPDATE和多数的SHOW语句。目前不支持其它语句。

以下例子显示了预备一个语句的两种方法。该语句用于在给定了两个边的长度时,计算三角形的斜边。

第一个例子显示如何通过使用文字字符串来创建一个预制语句,以提供语句的文本:

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;

预制语句的SQL语法不能被用于带嵌套的风格中。也就是说,被传递给PREPARE的语句本身不能是一个PREPARE, EXECUTE或DEALLOCATE PREPARE语句。

预制语句的SQL语法与使用预制语句API调用不同。例如,您不能使用mysql_stmt_prepare() C API函数来预备一个PREPARE, EXECUTE或DEALLOCATE PREPARE语句。

预制语句的SQL语法可以在已存储的过程中使用,但是不能在已存储的函数或触发程序中使用。

猜你喜欢

转载自blog.csdn.net/wu_zhiyuan/article/details/130273259