zoukankan      html  css  js  c++  java
  • 使用C语言调用mysql数据库编程实战以及技巧

    今天编写使用C语言调用mysql数据库编程实战以及技巧。为其它IT同行作为參考,当然有错误能够留言,共同学习。
    

    一、mysql数据库的C语言经常使用接口API
    1.首先当然是链接数据库mysql_real_connect,原型例如以下:
    MYSQL * STDCALL mysql_real_connect(
    MYSQL *mysql, const char *host,
    const char *user,
    const char *passwd,
    const char *db,
    unsigned int port,
    const char *unix_socket,
    unsigned long clientflag);
    第一个參数mysql是C语言api中一个很重要的变量。里面内存很丰富。有port,dbname,charset等连接基本參数。它也包括了一个叫 st_mysql_methods的结构体变量,该变量里面保存着许多函数指针。这些函数指针将会在数据库连接成功以后的各种数据操作中被调用。

    mysql_real_connect函数中各參数,基本都是顾名思意。

    2.连接数据库成功之后就能够使用mysql_query运行sql语句。原型例如以下:
    int STDCALL mysql_query(MYSQL *mysql, const char *q);
    第一个參数上面已经介绍过。第二个參数为要运行的sql语句,主要就是运行SQL语句的增、删、改、查等功能。


    这个函数整体就两步:
    (1)发送sql语句,事实上就一个socket发送sql 语句,加上mysql固定的协议头。
    (2)然后就是接受结果,这里将会调用MYSQL变量中的st_mysql_methods中的read_query_result函数指针

    a 假设包括二进制数据的查询,要使用mysql_real_query.

    b 检查受查询影响的行数:
    my_ulonglong mysql_affected_rows(MYSQL *connection);
    my_ulonglong是无符号长整形,为%lu格式
    这个函数返回受之前运行update,insert或delete查询影响的行数。

    #include    <stdio.h>
    #include    <string.h>
    #include    <stdlib.h>
    #include    <math.h>
    
    #include "/usr/local/mysql/include/mysql.h"
    
    static MYSQL mysql, *sock;
    char sql[1024];
    MYSQL_RES *res=NULL;
    MYSQL_ROW row ;
    int num_fields;
    int num_rows = 0;
    
    int main(){
        memset(sql, 0x00, sizeof(sql));
        mysql_init(&mysql);   
    
        if(!(sock = mysql_real_connect(&mysql, 
            (char *)"localhost", (char *)"ebipcs", 
            (char *)"Dcep2vUnAX", (char *)"ebipcs",
             0, NULL, 0))){
            printf( "Couldn't connect to DB!
    
    %s
    
    ", mysql_error(&mysql));
            return 0 ;
        }
    
        if(sock){
            printf( "SUCCESS
    " );
        }else{
            printf( "FAIL
    " );
            return 0;
        }
        sprintf(sql,"update cisaddressinfo set cisaddressinfo.addressseqno = '2' where cisaddressinfo.customid='199999900000000000015';");
        if(mysql_query(sock, sql)) {
             printf("mysql_query[%d] [%s]!
    ", mysql_errno(sock), mysql_error(sock));
             return -1;
         }
        if( !(mysql_affected_rows( sock )) ){
            printf("update OK
    ");
        }else{
            printf("update Fail
    ");
        }
        if(mysql_errno(sock)){
            printf("mysql_affected_rows[%d] [%s]!
    ", mysql_errno(sock), mysql_error(sock));
        }
        return 0;
    }

    3.存储运行结果
    SQL最常见的用法是提取数据而不是插入或更新数据。

    数据是用select语句提取的
    C应用程序提取数据一般须要4个步骤:
    1、运行查询
    2、提取数据
    3、处理数据
    4、必要的清理工作
    就像之前的insert和update一样,使用mysql_query来发送SQL语句,然后使用mysql_store_result或mysql_use_result来提取数据,详细使用哪个语句取决于你想怎样提取数据。接着,将使用一系列mysql_fetch_row来处理数据。最后。使用mysql_free_result释放查询占用的内存资源。

    a 一次提取全部数据:mysql_store_result
    假设mysql_query返回成功,那么我们就通过mysql_store_result函数来读取结果。原型例如以下:
    MYSQL_RES * STDCALL mysql_store_result(MYSQL *mysql);
    该函数会调用MYSQL变量中的st_mysql_methods中的 read_rows函数指针来获取查询的结果。同一时候该函数会返回MYSQL_RES 这样一个变量,该变量主要用于保存查询的结果。同一时候该函数malloc了一片内存空间来存储查询过来的数据,所以我们一定要记的 free(result),不然是肯定会造成内存泄漏的。

    运行完mysql_store_result以后,事实上数据都已经在MYSQL_RES 变量中了。
    相关函数:
    // 这是在成功调用mysql_query之后使用此函数,这个函数将立马保存在客户端中返回的全部数据。它返回一个指向结果集结构的指针,假设失败返回NULL
    MYSQL_RES *mysql_store_result(MYSQL *connection);
    // 这个函数接受由mysql_store_result返回的结果结构集,并返回结构集中的行数
    my_ulonglong mysql_num_rows(MYSQL_RES *result);
    // 这个函数从使用mysql_store_result得到的结果结构中提取一行,并把它放到一个行结构中。当数据用完或错误发生时返回NULL.
    MYSQL_ROW mysql_fetch_row(MYSQL_RES *resutl);
    // 这个函数用来在结果集中跳转。设置将会被下一个mysql_fetch_row操作返回的行。

    參数offset是一个行号。它必须是在0~结果总行数-1的范围内。

    传递
    // 0将会导致下一个mysql_fetch_row调用返回结果集中的第一行。


    void mysql_data_seek(MYSQL_RES *result, my_ulonglong offset);
    //返回一个偏移值,它用来表示结果集中的当前位置。它不是行号,不能把它用于mysql_data_seek
    MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES *result);
    // 这将在结果集中移动当前的位置。并返回之前的位置
    MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET offset);
    // 完毕全部对数据的操作后。必须总是调用这个来善后处理
    void mysql_free_result(MYSQL_RES *result);

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "mysql.h"
    #include "errmsg.h"
    #include "mysqld_error.h"
    
    MYSQL conn;
    MYSQL_RES *res_ptr;
    MYSQL_ROW sqlrow;
    
    void connection(const char* host, const char* user, const char* password, const char* database) {
        mysql_init(&conn); // 注意取地址符&
    
        if (mysql_real_connect(&conn, host, user, password, database, 0, NULL, 0)) {
            printf("Connection success!
    ");
        } else {
            fprintf(stderr, "Connection failed!
    ");
            if (mysql_errno(&conn)) {
                fprintf(stderr, "Connection error %d: %s
    ", mysql_errno(&conn), mysql_error(&conn));
            }
            exit(EXIT_FAILURE);
        }
    }
    
    int main (int argc, char *argv[]) {
    
        connection("localhost", "root", "shuang", "shuangde");
        int res = mysql_query(&conn, "SELECT * from student");
        if (res) {
            fprintf(stderr, "SELECT error: %s
    ", mysql_error(&conn));
        } else {
            res_ptr = mysql_store_result(&conn);
            if (res_ptr) {
                printf("Retrieved %lu rows
    ", (unsigned long)mysql_num_rows(res_ptr)); 
                while ((sqlrow = mysql_fetch_row(res_ptr))) {
                    printf("Fetched data...
    ") ;
                }
                if (mysql_errno(&conn)) {
                    fprintf(stderr, "Retrive error: %s
    ", mysql_error(&conn));
                }
                mysql_free_result(res_ptr);
            } 
        }
        mysql_close(&conn);
        exit(EXIT_SUCCESS);
    }

    b 一次提取一行数据:mysql_use_result
    用法和mysql_store_result全然一样。把上面代码的mysql_store_result改为mysql_use_result就可以。
    mysql_use_result具备资源管理方面的实质性优点,更好地平衡了网络负载。以及降低了可能很大的数据带来的存储开销,可是不能与mysql_data_seek、mysql_row_seek、mysql_row_tell、mysql_num_rows一起使用。假设数据比較少,用mysql_store_result更好。

    处理返回的数据相关函数和定义:
    // 返回结果集中的字段(列)数目
    unsigned int mysql_field_count(MYSQL *connection);
    // 将元数据和数据提取到一个新的结构中
    MYSQL_FIELD *mysql_fetch_field(MYSQL *result);
    // 这个函数用来覆盖当前的字段编号。该编号会随着每次mysql_fetch_field调用而自己主动添加。假设给offset传递0,那么将跳回第1列
    MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL *result, MYSQL_FIELD_OFFSET offset);
    // MYSQL_FIELD定义在sql.h中,是指向字段结构数据的指针,有关于列的信息。

    有成员:
    char *name; // 列名,为字符串
    char *table; // 列所属表名
    char *def; // 假设调用mysql_list_fields。它将包括该列的默认值
    enum enum_field_types type; // 列类型
    unsigned int length; // 列宽
    unsigned int max_length; // 假设使用mysql_store_result,它将包括以字节为单位的提取的最长列值的长度,假设使用mysql_use_result,将不会被设置
    unsigned int flags; // 关于列定义的标志,与得到的数据无关.常见的标志的含义有:
    // NOT_NULL_FLAG
    // PRI_KEY_FLAG
    // UNSIGNED_FLAG
    // AUTO_INCREMENT_FLAG
    // BINARY_FLAG等
    unsigned int decimals; // 小数点后的数字个数。
    // 列类型相当广泛,完整的列表见头文件mysql_com.h,常见的有:
    // FIELD_TYPE_DECIMAL
    // FIELD_TYPE_LONG
    // FIELD_TYPE_STRING
    // FIELD_TYPE_VAR_STRING
    //一个特别实用的提前定义宏: IS_NUM,当字段类型为数字时,返回true

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "mysql.h"
    #include "errmsg.h"
    #include "mysqld_error.h"
    
    
    MYSQL conn;
    MYSQL_RES *res_ptr;
    MYSQL_ROW sqlrow;
    
    void connection(const char* host, const char* user, const char* password, const char* database) {
        mysql_init(&conn); // 注意取地址符&
    
        if (mysql_real_connect(&conn, host, user, password, database, 0, NULL, 0)) {
            printf("Connection success!
    ");
        } else {
            fprintf(stderr, "Connection failed!
    ");
            if (mysql_errno(&conn)) {
                fprintf(stderr, "Connection error %d: %s
    ", mysql_errno(&conn), mysql_error(&conn));
            }
            exit(EXIT_FAILURE);
        }
    }
    
    void display_row() {
        unsigned int field_count = mysql_field_count(&conn);
        int i = 0;
        while (i < field_count) {
            if (sqlrow[i]) printf("%s ", sqlrow[i]);
            else printf("NULL");
            i++;
        }
        printf("
    ");
    }
    
    void display_header() {
        MYSQL_FIELD *field_ptr;
        printf("Column details:
    ");
        while ((field_ptr = mysql_fetch_field(res_ptr)) != NULL) {
            printf("	 Name: %s
    ", field_ptr->name);   
            printf("	 Table: %s
    ", field_ptr->table); 
            printf("	 Type: ");
            if (IS_NUM(field_ptr->type)) {
                printf("Numeric field
    ");  
            } else {
                switch(field_ptr->type) {
                    case FIELD_TYPE_VAR_STRING:
                        printf("VARCHAR
    ");
                        break;
                    case FIELD_TYPE_LONG:
                        printf("LONG");
                        break;
                    default:
                        printf("Type is %d, check in msyql_com.h
    ", field_ptr->type);
                }   
            }
            printf("	 Max width %ld
    ", field_ptr->length);
            if (field_ptr->flags & AUTO_INCREMENT_FLAG)
                printf("	 Auto increments
    ");
            printf("
    ");
        }
    }
    
    int main (int argc, char *argv[]) {
    
        connection("localhost", "root", "shuang", "shuangde");
        int res = mysql_query(&conn, "SELECT * from student");
        if (res) {
            fprintf(stderr, "SELECT error: %s
    ", mysql_error(&conn));
        } else {
            res_ptr = mysql_use_result(&conn);
            if (res_ptr) {
                int first = 1;
                while ((sqlrow = mysql_fetch_row(res_ptr))) {
                    if (first) {
                        display_header();
                        first = 0;  
                    }
                    display_row();
                }
                if (mysql_errno(&conn)) {
                    fprintf(stderr, "Retrive error: %s
    ", mysql_error(&conn));
                }
                mysql_free_result(res_ptr);
            } 
        }
        mysql_close(&conn);
        exit(EXIT_SUCCESS);
    }

    使用技巧:
    a 关于MYSQL MYSQL_RES 类型变量定义及free的问题。
    使用例如以下方式,会更好一些。
    定义: MYSQL_RES *res=NULL;
    使用:res = mysql_store_result( m_sock )
    释放:if(res)
    {mysql_free_result( res ); res=NULL}
    依据以上规则。我们定义一个宏:
    *#define MYSQLFREE(a)
    if( a != NULL )
    {
    mysql_free_result( a );
    a=NULL;
    }
    使用的时候:MYSQLFREE(res)

  • 相关阅读:
    (引)spring学习笔记1.什么是控制反转
    Arduino 各种模块篇 步进电机 step motor 舵机 servo 直流电机 总复习
    Raspberry Pi Wireless Adaptor
    Pyramid 使用总结1
    Arduino 各种模块篇 人体红外感应模块 proximity sensor
    Pyramid 使用总结2
    Webcam Streaming Desktop Recording on Linux for ubuntu or its destros
    Arduino 各种模块篇 步进电机 step motor( 不用库,不用shield, 纯)
    Arduino 各种模块篇 motor shield 电机扩展板(舵机、直流电机、步进电机party)
    转载 stepper motors
  • 原文地址:https://www.cnblogs.com/jhcelue/p/7352668.html
Copyright © 2011-2022 走看看