通过C语言的API预处理管理MySQL

一、C的API预处理语句

MySQL客户端/服务器协议提供了预处理语句。该功能采用了由mysql_stmt_init()初始化函数返回的MYSQL_STMT语句处理程序数据结构。对于多次执行的语句,预处理执行是一种有效的方式。首先对语句进行解析,为执行作好准备。接下来,在以后使用初始化函数返回的语句句柄执行一次或多次。对于多次执行的语句,预处理执行比直接执行快,主要原因在于,仅对查询执行一次解析操作。在直接执行的情况下,每次执行语句时,均将进行查询。此外,由于每次执行预处理语句时仅需发送参数的数据,从而减少了网络通信量。预处理语句的另一个优点是,它采用了二进制协议,从而使得客户端和服务器之间的数据传输更有效率。

 二、API预处理语句的数据类型

预处理语句主要使用MYSQL_STMT和MYSQL_BIND数据结构。第3种结构MYSQL_TIME用于传输暂时性数据。

  • MYSQL_STMT:该结构表示预处理语句。通过调用mysql_stmt_init()创建语句,返回语句句柄,即指向MYSQL_STMT的指针。该句柄用户所有后续的与语句有关的函数,直至使用mysql_stmt_close()关闭了它为止。
  • MYSQL_BIND:该结构用于语句输入(发送给服务器的数据值)和输出(从服务器返回的结果值)。对于输入,它与mysql_stmt_bind_param()一起使用,用于将参数数据值绑定到缓冲区上,以供mysql_stmt_execute()使用。对于输出,它与mysql_stmt_bind_result()一起使用,用于绑定结果缓冲区,以便用于with mysql_stmt_fetch()以获取行。要想使用MYSQL_BIND结构,应将其内容置为0以便初始化它,然后对其进行设置,恰当地描述它。
  • MYSQL_TIME:该结构用于将DATE、TIME、DATETIME和TIMESTAMP数据直接发送到服务器,或从服务器直接接收这类数据。将MYSQL_BIND结构的buffer_type成员设置为临时值之一,并将buffer成员设置为指向MYSQL_TIME结构,即可实现该点。

MYSQL_TIME结构包含下述成员:

  • 年份:unsigned int year
  • 月份:unsigned int month
  • 天:unsigned int day
  • 小时:unsigned int hour
  • 分钟:unsigned int minute
  • 秒:unsigned int second
  • my_bool neg:用于指明时间是否为负数
  • unsigned long second_part:秒的分数部分,该成员目前不使用

在下面的表格中,给出了可在MYSQL_BIND结构的buffer_type成员中指定的允许值。在该表中,还给出了与每个buffer_type值最接近的对应SQL类型,对于数值和临时类型,给出了对应的C类型:

三、预处理语句的执行步骤

要想准备和执行语句,应用程序必须采取下述步骤:

  1. 用msyql_stmt_init()创建预处理语句句柄。要想在服务器上准备预处理语句,可调用mysql_stmt_prepare(),并为其传递包含SQL语句的字符串。
  2. 如果语句生成了结果集,调用mysql_stmt_result_metadata()以获得结果集元数据。虽然与包含查询返回列的结果集不同,该元数据本身也采用了结果集的形式。元数据结果集指明了结果中包含多少列,并包含每一列的信息。
  3. 使用mysql_stmt_bind_param()设置任何参数的值。必须设置所有参数。否则,语句执行将返回错误,或生成无法预料的结果。
  4. 调用mysql_stmt_execute()执行语句。
  5. 如果语句生成了结果集,捆绑数据缓冲,通过调用mysql_stmt_bind_result(),检索行值。
  6. 通过重复调用mysql_stmt_fetch(),按行将数据提取到缓冲区,直至未发现更多行为止。
  7. 通过更改参数值并再次执行语句,重复步骤3到步骤6。

调用mysql_stmt_prepare()时,MySQL客户端/服务器协议将执行下述动作:

  • 服务器解析语句,并通过赋值语句ID将OK状态发回客户端。此外,如果它是面向结果集的语句,还将发送总的参数数目,列计数和元数据。在此调用过程中,服务器将检查语句的所有语法和语义。
  • 客户端采用该语句ID用于进一步操作,以便服务器能从其语句池中识别语句。

调用mysql_stmt_execute()时,MySQL客户端/服务器协议将执行下述动作:

  • 客户端使用语句句柄,并将参数数据发送到服务器。
  • 服务器使用由客户端提供的ID来识别语句,用新提供的数据替换参数标记符,并执行语句。如果语句生成了结果集,服务器将数据发回客户端。否则,服务器会将发送OK状态,以及总的变更、删除和插入行数。

调用mysql_stmt_fetch()时,MySQL客户端/服务器协议将执行下述动作:

  • 客户端按行从信息包读取数据,并通过执行必要的转换操作将其放入应用程序数据缓冲中。如果应用程序的缓冲类型与服务器返回的字段类型相同,转换十分简明。

如果出现了错误,可分别使用mysql_stmt_errno()、mysql_stmt_error()和mysql_stmt_sqlstate()获取语句错误代码、错误消息和SQLSTATE值。

四、相关函数介绍

1.mysql_stmt_init()

MYSQL_STMT *mysql_stmt_init(MYSQL *mysql) 

描述:创建MYSQL_STMT句柄。对于该句柄,应使用mysql_stmt_close(MYSQL_STMT *)释放。

返回值:成功时,返回指向MYSQL_STMT结构的指针。如果内存溢出,返回NULL。

错误:CR_OUT_OF_MEMORY:内存溢出。 

2.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(),将参数标记符与应用程序变量绑定在一起。

返回值:如果成功处理了语句,返回0。如果出现错误,返回非0值。 

错误:

  • CR_COMMANDS_OUT_OF_SYNC:以不恰当的顺序执行了命令。
  • CR_OUT_OF_MEMORY:内存溢出。
  • CR_SERVER_GONE_ERROR:MySQL服务器不可用。
  • CR_SERVER_LOST:查询过程中,与服务器的连接丢失。
  • CR_UNKNOWN_ERROR:出现未知错误。

如果准备操作失败(即mysql_stmt_prepare()返回非0值),可通过调用mysql_stmt_error()获取错误消息。

3.mysql_stmt_param_count()

unsigned long mysql_stmt_param_count(MYSQL_STMT *stmt) 

描述:返回预处理语句中参数标记符的数目。

返回值:表示语句中参数数目的无符号长整数。 

4.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值。 

5.mysql_stmt_error()

const char *mysql_stmt_error(MYSQL_STMT *stmt) 

返回值:描述了错误的字符串。如果未出现错误,返回空字符串。 

6.mysql_stmt_execute()

int mysql_stmt_execute(MYSQL_STMT *stmt) 

描述:

mysql_stmt_execute()执行与语句句柄相关的预处理查询。在该调用期间,将当前绑定的参数标记符的值发送到服务器,服务器用新提供的数据替换标记符。如果语句是UPDATE、DELETE或INSERT,通过调用mysql_stmt_affected_rows(),可发现更改、删除或插入的总行数。如果这是诸如SELECT等能生成结果集的语句,调用任何其他能导致查询处理的函数之前,必须调用mysql_stmt_fetch()来获取数据。

返回值:如果执行成功,返回0。如果出现错误,返回非0值。

 7.mysql_stmt_result_metadata()

MYSQL_RES *mysql_stmt_result_metadata(MYSQL_STMT *stmt) 

描述:

如果传递给mysql_stmt_prepare()的语句能够成生结果集,mysql_stmt_result_metadata()将以指针的形式返回结果集元数据,该指针指向MYSQL_RES结构,可用于处理元信息,如总的字段数以及单独的字段信息。该结果集指针可作为参量传递给任何基于字段且用于处理结果集元数据的API函数,如:完成操作后,应释放结果集结构,可通过将其传递给mysql_free_result()完成。它与释放通过mysql_store_result()调用获得的结果集的方法类似。

返回值:MYSQL_RES结果结构。如果不存在关于预处理查询的任何元信息,返回NULL。

错误:

  • CR_OUT_OF_MEMORY:内存溢出。
  • CR_UNKNOWN_ERROR:出现未知错误。 

8.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_result(),并传递类型、地址、以及长度缓冲的地址。在25.2.5节,“C API预处理语句的数据类型”中,介绍了应设置的各MYSQL_BIND元素的成员。

返回值:如果绑定成功,返回0。如果出现错误,返回非0值。 

9.mysql_fetch_field()

MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result) 

描述:

返回采用MYSQL_FIELD结构的结果集的列。重复调用该函数,以检索关于结果集中所有列的信息。未剩余字段时,mysql_fetch_field()返回NULL。

每次执行新的SELECT查询时,将复位mysql_fetch_field(),以返回关于第1个字段的信息。调用mysql_field_seek()也会影响mysql_fetch_field()返回的字段。

如果调用了mysql_query()以在表上执行SELECT,但未调用mysql_store_result(),如果调用了mysql_fetch_field()以请求BLOB字段的长度,MySQL将返回默认的Blob长度(8KB)。之所以选择8KB是因为MySQL不知道BLOB的最大长度。应在日后使其成为可配置的。一旦检索了结果集,field->max_length将包含特定查询中该列的最大值的长度。

返回值:当前列的MYSQL_FIELD结构。如果未剩余任何列,返回NULL。

9.mysql_stmt_fetch()

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()之前,应用程序必须绑定所有列。

返回值:

不返回MYSQL_DATA_TRUNCATED,除非用mysql_options()启用了截短通报功能。返回该值时,为了确定截短的参数是哪个,可检查MYSQL_BIND参数结构的错误成员。  

10.mysql_stmt_store_result()

int mysql_stmt_store_result(MYSQL_STMT *stmt)

描述:

对于成功生成结果集的所有语句(SELECT、SHOW、DESCRIBE、EXPLAIN),而且仅当你打算对客户端的全部结果集进行缓冲处理时,必须调用mysql_stmt_store_result(),以便后续的mysql_stmt_fetch()调用能返回缓冲数据。对于其他语句,没有必要调用mysql_stmt_store_result(),但如果调用了它,也不会造成任何伤害或导致任何性能问题。通过检查mysql_stmt_result_metadata()是否返回NULL,可检测语句是否生成了结果集。更多信息,请参见25.2.7.22节,“mysql_stmt_result_metadata()”。注释:默认情况下,对于mysql_stmt_store_result()中的所有列,MySQL不计算MYSQL_FIELD->max_length,这是因为,计算它会显著降低mysql_stmt_store_result()的性能,而且大多数应用程序不需要max_length。如果打算更新max_length,可通过调用mysql_stmt_attr_set(MYSQL_STMT, STMT_ATTR_UPDATE_MAX_LENGTH, &flag)启用它。

返回值:如果成功完成了对结果的缓冲处理,返回0。如果出现错误,返回非0值。

二、执行插入、删除、修改等SQL语句

1.执行insert语句

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

#define HOST_IP     "localhost"
#define USER_NAME   "root"
#define USER_PWD    "root"
#define DB_NAME     "mydb"

#define DROP_SAMPLE_TABLE           "DROP TABLE IF EXISTS test_table"
#define CREATE_SAMPLE_TABLE         "CREATE TABLE test_table(col1 INT,\
                                    col2 VARCHAR(40),\
                                    col3 SMALLINT,\
                                    col4 TIMESTAMP)"
#define INSERT_SAMPLE               "INSERT INTO test_table(col1,col2,col3) VALUES(?, ?, ?)"

#define STRING_SIZE     50

int main() {
    MYSQL *mysql = NULL;

    //初始化
    mysql = mysql_init(NULL);
    if (mysql == NULL) {
        printf("mysql_init failde...\n");

        return  -1;
    }
    printf("mysql_init successfully...\n");

    //连接数据库
    mysql = mysql_real_connect(mysql, HOST_IP, USER_NAME, USER_PWD, DB_NAME, 0, NULL, 0);
    if (mysql == NULL) {
        printf("mysql_real_connect failed:%s\n", mysql_error(mysql));

        return -1;
    }
    printf("mysql_real_connect successfully...\n");

    MYSQL_STMT *stmt; //预处理的句柄
    MYSQL_BIND bind[3]; //绑定变量
    my_ulonglong affected_rows;
    int param_count;
    short small_data;
    int int_data;
    char str_data[STRING_SIZE];
    unsigned long str_length;
    bool is_null;

    //创建表 
    if (mysql_query(mysql, DROP_SAMPLE_TABLE)) {
        printf("drop table failed:%s\n", mysql_error(mysql));
        mysql_close(mysql);

        return  -1;
    }

    //删除表
    if (mysql_query(mysql, CREATE_SAMPLE_TABLE)) {
        printf("create table failed:%s\n", mysql_error(mysql));
        mysql_close(mysql);

        return  -1;
    }

    //预处理的初始化
    stmt = mysql_stmt_init(mysql);
    if (!stmt) {
        printf("mysql_stmt_init failed:out of memory\n");
        mysql_close(mysql);

        return -1;
    }

    //insert语句的预处理
    int ret = mysql_stmt_prepare(stmt, INSERT_SAMPLE, strlen(INSERT_SAMPLE));
    if (ret != 0) {
        printf("mysql_stmt_prepare failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }

    printf("mysql_stmt_prepare successfully...\n");

    //获得参数个数
    param_count = mysql_stmt_param_count(stmt);
    if (param_count != 3) {
        printf("invalid parameter count return by MySQL\n");
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }

    /* bind the data for all 3 parameters */

    /* INTEGER PARAM */
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = (char*)&int_data; //内存地址的映射
    bind[0].is_null = 0;
    bind[0].length = 0;

    /* STRING PARAM */
    bind[1].buffer_type = MYSQL_TYPE_STRING;
    bind[1].buffer = (char*)&str_data;
    bind[1].is_null = 0;
    bind[1].length = &str_length;

    /* SMALLINT PARAM */
    bind[2].buffer_type = MYSQL_TYPE_SHORT;
    bind[2].buffer = (char*)&small_data;
    bind[2].is_null = &is_null; //是否为null的指示器
    bind[2].length = 0;

    /* bind the buffers */
    //绑定变量,参数绑定
    if (mysql_stmt_bind_param(stmt, bind)) {
        printf("mysql_stmt_bind_param failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }

    //第一波赋值
    int_data = 10;
    strncpy(str_data, "MySQL", STRING_SIZE);
    str_length = strlen(str_data);

    /* INSERT SMALLINT data as NULL */
    is_null = 1; //指示插入的第三个字段是否为null

    /* excute the insert */
    //预处理的执行
    if (mysql_stmt_execute(stmt)) {
        printf("mysql_stmt_execute 1 failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }

    /* get the total number of affected rows */
    affected_rows = mysql_stmt_affected_rows(stmt); //预处理的影响条数
    printf("total affected rows(insert 1):%lu\n", (unsigned long) affected_rows);
    if (affected_rows != 1) {
        printf("invalid affected rows by MySQL\n");
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return -1;
    }

    //第二波赋值
    int_data = 1000;
    strncpy(str_data, "The most popular Open Source database", STRING_SIZE);
    str_length = strlen(str_data);
    small_data = 1000; /* smallint */
    is_null = 0; /* reset */

    if (mysql_stmt_execute(stmt)) {
        printf("mysql_stmt_execute 2 failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }

    affected_rows = mysql_stmt_affected_rows(stmt); //预处理的影响条数
    printf("total affected rows(insert 2):%lu\n", (unsigned long) affected_rows);
    if (affected_rows != 1) {
        printf("invalid affected rows by MySQL\n");
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return -1;
    }

    //关闭连接
    if (mysql_stmt_free_result(stmt)) {
        printf("failed while closing the stmt:%s\n", mysql_stmt_error(stmt));
    }
    mysql_close(mysql);

    return 0;
}

执行结果如下: 

2.执行update语句 

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

#define HOST_IP     "localhost"
#define USER_NAME   "root"
#define USER_PWD    "root"
#define DB_NAME     "mydb"

#define UPDATE_STUDENT_INFO     "UPDATE student SET name=?, chinese=?, english=?, math=? WHERE id=?"

int main() {
    MYSQL *mysql = NULL;

    //初始化
    mysql = mysql_init(NULL);
    if (mysql == NULL) {
        printf("mysql_init failde...\n");

        return  -1;
    }
    printf("mysql_init successfully...\n");

    //连接数据库
    mysql = mysql_real_connect(mysql, HOST_IP, USER_NAME, USER_PWD, DB_NAME, 0, NULL, 0);
    if (mysql == NULL) {
        printf("mysql_real_connect failed:%s\n", mysql_error(mysql));

        return -1;
    }
    printf("mysql_real_connect successfully...\n");

    MYSQL_STMT *stmt; //预处理的句柄
    MYSQL_BIND bind[5]; //绑定变量
    my_ulonglong affected_rows;
    int param_count;

    //预处理的初始化
    stmt = mysql_stmt_init(mysql);
    if (!stmt) {
        printf("mysql_stmt_init failed:out of memory\n");
        mysql_close(mysql);

        return -1;
    }

    //update语句的预处理
    int ret = mysql_stmt_prepare(stmt, UPDATE_STUDENT_INFO, strlen(UPDATE_STUDENT_INFO));
    if (ret != 0) {
        printf("mysql_stmt_prepare failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }

    printf("mysql_stmt_prepare successfully...\n");

    //获得参数个数
    param_count = mysql_stmt_param_count(stmt);
    if (param_count != 5) {
        printf("invalid parameter count return by MySQL\n");
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }

    /* bind the data for all 5 parameters */
    char name[] = "罗况子";
    int chinese = 99;
    int english = 90;
    int math = 90;
    int id = 2;
    unsigned long length = strlen(name);

    memset(bind, 0, sizeof (bind));
    bind[0].buffer_type = MYSQL_TYPE_STRING;
    bind[0].buffer = name;
    bind[0].is_null = 0;
    bind[0].length = &length;

    bind[1].buffer_type = MYSQL_TYPE_LONG;
    bind[1].buffer = (char*)&chinese;
    bind[1].is_null = 0;
    bind[1].length = 0;

    bind[2].buffer_type = MYSQL_TYPE_LONG;
    bind[2].buffer = (char*)&english;
    bind[2].is_null = 0;
    bind[2].length = 0;

    bind[3].buffer_type = MYSQL_TYPE_LONG;
    bind[3].buffer = (char*)&math;
    bind[3].is_null = 0;
    bind[3].length = 0;

    bind[4].buffer_type = MYSQL_TYPE_LONG;
    bind[4].buffer = (char*)&id;
    bind[4].is_null = 0;
    bind[4].length = 0;

    /* bind the buffers */
    //绑定变量,参数绑定
    if (mysql_stmt_bind_param(stmt, bind)) {
        printf("mysql_stmt_bind_param failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }

    /* excute the update */
    //预处理的执行
    if (mysql_stmt_execute(stmt)) {
        printf("mysql_stmt_execute 1 failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }

    /* get the total number of affected rows */
    affected_rows = mysql_stmt_affected_rows(stmt); //预处理的影响条数
    printf("total affected rows(iupdate 1):%lu\n", (unsigned long) affected_rows);
    if (affected_rows != 1) {
        printf("invalid affected rows by MySQL\n");
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return -1;
    }

    //关闭连接
    if (mysql_stmt_free_result(stmt)) {
        printf("failed while closing the stmt:%s\n", mysql_stmt_error(stmt));
    }
    mysql_close(mysql);

    return 0;
}

执行之前数据表如下所示:

执行之后数据表如下所示:

3.执行SELECT语句

获取列字段的名称和大小:

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

#define HOST_IP     "localhost"
#define USER_NAME   "root"
#define USER_PWD    "root"
#define DB_NAME     "mydb"

#define SELECT_STUDENT_INFO     "SELECT * from student"

int main() {
    MYSQL *mysql = NULL;
     MYSQL_STMT *stmt = NULL; //预处理的句柄
     MYSQL_RES *meta_result = NULL;
     MYSQL_FIELD *field = NULL;

    //初始化
    mysql = mysql_init(NULL);
    if (mysql == NULL) {
        printf("mysql_init failde...\n");

        return  -1;
    }
    printf("mysql_init successfully...\n");

    //连接数据库
    mysql = mysql_real_connect(mysql, HOST_IP, USER_NAME, USER_PWD, DB_NAME, 0, NULL, 0);
    if (mysql == NULL) {
        printf("mysql_real_connect failed:%s\n", mysql_error(mysql));

        return -1;
    }
    printf("mysql_real_connect successfully...\n");

    //预处理的初始化
    stmt = mysql_stmt_init(mysql);
    if (!stmt) {
        printf("mysql_stmt_init failed:out of memory\n");
        mysql_close(mysql);

        return -1;
    }

    //select语句的预处理
    int ret = mysql_stmt_prepare(stmt, SELECT_STUDENT_INFO, strlen(SELECT_STUDENT_INFO));
    if (ret != 0) {
        printf("mysql_stmt_prepare failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }

    printf("mysql_stmt_prepare successfully...\n");

    /* excute the insert */
    //预处理的执行
    if (mysql_stmt_execute(stmt)) {
        printf("mysql_stmt_execute 1 failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }

    meta_result = mysql_stmt_result_metadata(stmt);
    if (!meta_result) {
        printf("mysql_stmt_result_metadata failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return -1;
    }

    while ((field = mysql_fetch_field(meta_result))) {
        printf("Column Name:%s\n", field->name);
        printf("Data Type:%d\n", field->type);
        printf("-----------\n");
    }

    //关闭连接
	mysql_free_result(meta_result);
    if (mysql_stmt_free_result(stmt)) {
        printf("failed while closing the stmt:%s\n", mysql_stmt_error(stmt));
    }
mysql_stmt_close(stmt); mysql_close(mysql); return 0; }

输出结果如下:  

 获取数据表的行数:

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

#define HOST_IP     "localhost"
#define USER_NAME   "root"
#define USER_PWD    "root"
#define DB_NAME     "mydb"

#define STUDENT_INFO_COUNT     "SELECT COUNT(*) from student"

int main() {
    MYSQL *mysql = NULL;
     MYSQL_STMT *stmt = NULL; //预处理的句柄
     MYSQL_BIND bind[1]; //for the row count
     unsigned long row_count = 0;

    //初始化
    mysql = mysql_init(NULL);
    if (mysql == NULL) {
        printf("mysql_init failde...\n");

        return  -1;
    }
    printf("mysql_init successfully...\n");

    //连接数据库
    mysql = mysql_real_connect(mysql, HOST_IP, USER_NAME, USER_PWD, DB_NAME, 0, NULL, 0);
    if (mysql == NULL) {
        printf("mysql_real_connect failed:%s\n", mysql_error(mysql));

        return -1;
    }
    printf("mysql_real_connect successfully...\n");

    //预处理的初始化
    stmt = mysql_stmt_init(mysql);
    if (!stmt) {
        printf("mysql_stmt_init failed:out of memory\n");
        mysql_close(mysql);

        return -1;
    }

    int ret = mysql_stmt_prepare(stmt, STUDENT_INFO_COUNT , strlen(STUDENT_INFO_COUNT));
    if (ret != 0) {
        printf("mysql_stmt_prepare failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }
    printf("mysql_stmt_prepare successfully...\n");

    memset(bind, 0, sizeof(bind));
    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = &row_count;

    if (mysql_stmt_bind_result(stmt, bind) != 0) {
        printf("mysql_stmt_bind_result failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return -1;
    }

    //预处理的执行
    if (mysql_stmt_execute(stmt)) {
        printf("mysql_stmt_execute 1 failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }

    if (mysql_stmt_store_result(stmt) != 0) {
        printf("mysql_stmt_store_result failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }

    mysql_stmt_fetch(stmt);

    printf("Row count:%lu\n", row_count);

    //关闭连接
    if (mysql_stmt_free_result(stmt)) {
        printf("failed while closing the stmt:%s\n", mysql_stmt_error(stmt));
    }
mysql_stmt_close(stmt); mysql_close(mysql); return 0; }

数据表查询结果:  

执行后输出结果:

获取数据表每行的数据:

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

#define HOST_IP     "localhost"
#define USER_NAME   "root"
#define USER_PWD    "root"
#define DB_NAME     "mydb"

#define SELECT_STUDENT_INFO     "SELECT id,name,chinese,english,math from student"

int main() {
    MYSQL *mysql = NULL;
     MYSQL_STMT *stmt = NULL; //预处理的句柄
     MYSQL_BIND bind[5];
     int id, chinese, english, math;
     char name[256] = {0};

    //初始化
    mysql = mysql_init(NULL);
    if (mysql == NULL) {
        printf("mysql_init failde...\n");

        return  -1;
    }
    printf("mysql_init successfully...\n");

    //连接数据库
    mysql = mysql_real_connect(mysql, HOST_IP, USER_NAME, USER_PWD, DB_NAME, 0, NULL, 0);
    if (mysql == NULL) {
        printf("mysql_real_connect failed:%s\n", mysql_error(mysql));

        return -1;
    }
    printf("mysql_real_connect successfully...\n");

    //预处理的初始化
    stmt = mysql_stmt_init(mysql);
    if (!stmt) {
        printf("mysql_stmt_init failed:out of memory\n");
        mysql_close(mysql);

        return -1;
    }

    int ret = mysql_stmt_prepare(stmt, SELECT_STUDENT_INFO , strlen(SELECT_STUDENT_INFO));
    if (ret != 0) {
        printf("mysql_stmt_prepare failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }
    printf("mysql_stmt_prepare successfully...\n");

    memset(bind, 0, sizeof(bind));

    bind[0].buffer_type = MYSQL_TYPE_LONG;
    bind[0].buffer = (char*)&id;

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

    bind[2].buffer_type = MYSQL_TYPE_LONG;
    bind[2].buffer = (char*)&chinese;

    bind[3].buffer_type = MYSQL_TYPE_LONG;
    bind[3].buffer = (char*)&english;

    bind[4].buffer_type = MYSQL_TYPE_LONG;
    bind[4].buffer = (char*)&math;

    if (mysql_stmt_bind_result(stmt, bind) != 0) {
        printf("mysql_stmt_bind_result failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return -1;
    }

    //预处理的执行
    if (mysql_stmt_execute(stmt) != 0) {
        printf("mysql_stmt_execute 1 failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }

    if (mysql_stmt_store_result(stmt) != 0) {
        printf("mysql_stmt_store_result failed:%s\n", mysql_stmt_error(stmt));
        mysql_stmt_close(stmt);
        mysql_close(mysql);

        return  -1;
    }

    while (1) {
        ret = mysql_stmt_fetch(stmt);
        if (ret == 100) {
            break;
        }
        printf("id:%d,name:%s,chinese:%d,english:%d,math:%d\n", id, name, chinese, english, math);
    }

    //关闭连接
    if (mysql_stmt_free_result(stmt)) {
        printf("failed while closing the stmt:%s\n", mysql_stmt_error(stmt));
    }
    mysql_stmt_close(stmt);
    mysql_close(mysql);

    return 0;
}

执行后输出结果:

  

posted @ 2023-12-09 10:56  TechNomad  阅读(85)  评论(0编辑  收藏  举报