Linux使用C语言连接MYSQL

1、连接例程:
首先,使用mysql_init来初始化连接剧柄:
#include

初始化之后,你必须使用mysql_real_connect来向一个连接提供参数:
    MYSQL *mysql_real_connect(MYSQL *connection,//指向已经被mysql_init初始化过的结构
                const char *server_host,//可以是主机名,也可以是IP地址(本地可以是localhost)
                const char *sql_user_name,//使用者
                const char *sql_password,//使用者密码(密码会再被传输的过程中加密)
                const char *db_name,//数据库名字
                unsigned int port_number,//NULL,这两个为默认值就行
                const char *unix_socket_name,//0
                unsigned int flags);//这是改变协议的特性,位模式进行OR操作
    如果无法连接,它将返回NULL。mysql_error函数可以提供又帮助的信息。
使用完连接之后,通常在程序退出时,使用mysql_close:
void mysql_close(MYSQL *connection);
这将关闭连接。如果连接时由mysql_init建立的,mysql结构会被释放。指针将会失效并无法再次使用。逗留一个不需
要的连接是对资源的浪费,但是重新打开连接也会带来额外的开销,所以你必须自己权衡何时使用这些选项。

mysql_options例程(仅能在mysql_init和mysql_read_connect之间调用)可以设置一些选项:
int mysql_options(MYSQL *connection,enum option_to_set,const char *argument);

因为mysql_options一次只能设置一个选项,所以每设置一个选项就得调用它一次。你可以根据需要多次使用它,只
要它出现在mysql_init和mysql_real_connect之间即可。并不是所有的选项都是char类型,因此它们必须被转换
成const char *.  

enum选项          实际参数类型          说明
MYSQL_OPT_CONNECT_TIMEOUT   const unsigned int *        连接超时之前的等待秒数
MYSQL_OPT_COMPRESS      None,使用NULL         网络连接中使用压缩机制
MYSQL_INIT_COMMAND      const char *            每次连接建立后发送的命令
一次成功的调用将返回0。因为它仅仅是用来设置标志,所以失败总是意味这使用了一个无效的选项。

例子:
如果要设置连接超时时间为7秒,我们使用的代码片段如下所示:
unsigned int timeout=7;
    ...
    connection=mysql_init(NULL);
    ret=mysql_options(connection,MYSQL_OPT_CONNECT_TIMEOUT,(const char *)&timeout);

    if(ret){
        /*Handle error*/
    }
    connection=mysql_real_connect(connection ...);
下面我们使用一个简洁的程序来测试一下:
首先为用户设置一个新的密码(在下面的代码中,是本机上的rick的用户),然后创建要连接的数据库foo。
$ mysql -u root -p
    mysql> grant all on *.* to rick@localhost identified by '123456'

    mysql> \q
    $ mysql -u rick -p
    mysql> create database foo;
    mysql> \q 
使用sql文件进行批处理,这个文件为create_children.sql:
create table children (
    childno int(11) not null auto_increment primary key,
    fname varchar(30),
    age int(11)
    );

    insert into children(childno,fname,age) values(1,'Jenny',21);
    insert into children(childno,fname,age) values(2,'Andrew',17);
    insert into children(childno,fname,age) values(3,'Gavin',8);
    insert into children(childno,fname,age) values(4,'DUncan',5);
    insert into children(childno,fname,age) values(5,'Alex',4);
    insert into children(childno,fname,age) values(6,'Adrian',9);
重新登录:
$ mysql -u rick -p foo //或者是:mysql -u rick --password=123456 foo
    mysql> source create_children.sql //或者是:\. create_children.sql
下面的程序connect1.c,它以用户名rick和密码123456来连接本机服务器上名为foo的数据库:
#include 
    #include 

    #include "mysql.h"

    int main(int argc,char *argv[]){
        MYSQL *conn_ptr;

        conn_ptr=mysql_init(NULL);//一般都是传递一个NULL
        if(!conn_ptr){
            fprintf(stderr,"mysql_init failed\n");
            return EXIT_FAILURE;
        }

        conn_ptr=mysql_real_connect(conn_ptr,"localhost","rick","123456","foo",0,NULL,0);
        if(conn_ptr){
            printf("COnnection success\n");
        }
        else
        {
            printf("Connection failed\n");
        }
        mysql_close(conn_ptr);

        return EXIT_SUCCESS;
    }
下面是编译:
1、gcc -I/usr/include/mysql connect1.c -L/usr/lib/mysql  -L/usr/lib64/mysql  -lmysqlclient -o connect1
我的是这种
2、gcc -I/usr/include/mysql connect1.c -L/usr/lib/mysql  -lmysqlclient -o connect1

执行:(到这里你就成功了)
$ ./connect1
Connection success

错误处理
unsigned int mysql_errno(MYSQL *connection);
char *mysql_error(MYSQL *connection);
你可以通过调用mysql_error并传递连接结构来获得错误码,它通常都是非0值。
如果未设定错误码,它将返回0.
每次调用库都会跟新错误码,所以你只能得到最后一个执行命令的错误码。

但是上面两个检查是例外,它们不会导致错误码的更新。

mysql_errno的返回值就是实际错误码,它们在头文件errmsg.h或者mysqld_error.h中定义。
这两个文件都可以在MySQL的include目录中找到。
前者报告客户端错误,后者关注服务器错误。

如果你喜欢文本错误信息,也可以调用mysql_error,它提供了有意义的文本信息而不是单调的错误码。

下面的connect2.c它例出了如何使用非动态分配的连接结构,以及如何编写一些基本的错误处理代码:
#include 
    #include 
    #include 

    int main(int argc,char *argv[])
    {
        MYSQL my_connection;

        mysql_init(&my_connection);
        if(mysql_real_connect(&my_connection,"localhost","rick","I do not know","foo",0,NULL,0)){
            printf("Connection success\n");
            mysql_close(&my_connection);
        }
        else
        {
            fprintf(stderr,"Connection_failed\n");
            if(mysql_errno(&my_connection)){
                fprintf(stderr,"Connection error %d: %s\n",
                mysql_errno(&my_connection),mysql_error(&my_connection));
            }
        }
        return EXIT_SUCCESS;
    }
下面是编译:
1、gcc -I/usr/include/mysql connect1.c -L/usr/lib/mysql  -L/usr/lib64/mysql  -lmysqlclient -o connect1
我的是这种
2、gcc -I/usr/include/mysql connect1.c -L/usr/lib/mysql  -lmysqlclient -o connect1

执行:
$ ./connect2
Connection_failed
Connection error 1045: Access denied for user 'rick'@'localhost' (using password: YES)

执行SQL语句
int mysql_query(MYSQL *connection,const char *query);
成功,返回0.对于包含二进制数据的查询,你可以使用mysql_real_query。

检查受影响的函数:
my_ulonglong mysql_affected_rows(MYSQL *connection);

例子:
#include 
        #include 
        #include 

        int main(int argc,char *argv[])
        {
            MYSQL my_connection;
            int res;

            mysql_init(&my_connection);
            if(mysql_real_connect(&my_connection,"localhost",
                        "rick","123456","foo",0,NULL,0)){
                printf("Connection success\n");
                //当前是更新,此处可以替换为插入
                //mysql_query(&my_connection,"insert into children(fname,age) values('Ann',3)");
                res=mysql_query(&my_connection,"update children set age=4 where fname='Ann'");
                if(!res){
                    printf("updated %lu rows\n",(unsigned long)mysql_affected_rows(&my_connection));
                }
                else
                {
                    fprintf(stderr,"update error %d: %s\n",mysql_errno(&my_connection),mysql_error(&my_connection));
                }
                mysql_close(&my_connection);
            }
            else
            {
                fprintf(stderr,"Connection failed\n");
                if(mysql_errno(&my_connection)){
                    fprintf(stderr,"Connection error %d: %s\n",mysql_errno(&my_connection),mysql_error(&my_connection));
                }
            }
            return EXIT_SUCCESS;
        }
编译同上。

但是你也可以使用更传统的报告:
if(mysql_real_connect(&my_connection,"localhost","rick","123456","foo",0,NULL,CLIENT_FOUND_ROWS)){

};

发现插入的内容:
atuo_increment类型的列,它由mysql自动分配ID。
LAST_INSERT_ID()会发现每个用户对最后分配的值进行跟踪。

实验:提取由AUTO_INCREMENT生成的ID
MariaDB [foo]> insert into children(fname,age) values('Tom',13);
    Query OK, 1 row affected (0.00 sec)

    MariaDB [foo]> show tables;
    +---------------+
    | Tables_in_foo |
    +---------------+
    | children      |
    +---------------+
    1 row in set (0.00 sec)

    MariaDB [foo]> select last_insert_id();
    +------------------+
    | last_insert_id() |
    +------------------+
    |                2 |
    +------------------+
    1 row in set (0.00 sec)
每次插入一行,MySQL就分配一个新的id值并且跟踪它,使得你可以用LAST_INSERT_ID()来提取它。

实验:在C程序中使用自动分配的ID
程序名字:insert2.c
#include 
    #include 

    #include 

    int main(int argc,char *argv[]){
        MYSQL my_connection;
        MYSQL_RES *res_ptr;
        MYSQL_ROW sqlrow;

        int res;

        mysql_init(&my_connection);
        if(mysql_real_connect(&my_connection,"localhost","rick","123456","foo",0,NULL,0)){
            printf("Connection success\n");

            res=mysql_query(&my_connection,"insert into children(fname,age) values('Robert',7)");
            if(!res){
                printf("Inserted %lu rows\n",(unsigned long)mysql_affected_rows(&my_connection));
            }
            else{
                fprintf(stderr,"Insert error %d: %s\n",mysql_errno(&my_connection),mysql_error(&my_connection));
            }

            res=mysql_query(&my_connection,"select last_insert_id()");
            if(res){
                printf("select error: %s\n",mysql_error(&my_connection));
            }
            else{
                /*
                对于成功检索数据的每个查询(SELECT、SHOW、DESCRIBE、EXPLAIN),必须调用mysql_store_result()或
                mysql_use_result()。mysql_use_result()将初始化结果集检索,但并不像mysql_store_result()那样将结果集实际
                读取到客户端。它必须通过对mysql_fetch_row()的调用,对每一行分别进行检索
                */
                //MYSQL_RES *mysql_use_result(MYSQL *mysql)
                res_ptr=mysql_use_result(&my_connection);
                if(res_ptr){
                    //array mysql_fetch_row(int result) 
                    //获取查询结果集,其区别在于函数的返回值不是一个字符串,而是一个数组
                    while((sqlrow=mysql_fetch_row(res_ptr))){
                        printf("We inserted childno %s\n",sqlrow[0]);
                    }
                    //void mysql_free_result() 函数释放结果内存。
                    mysql_free_result(res_ptr);
                }
            }

            mysql_close(&my_connection);
        }
        else{
            fprintf(stderr,"Connection failed\n");
            if(mysql_errno(&my_connection)){
                fprintf(stderr,"Connection error %d: %s\n",
                    mysql_errno(&my_connection),mysql_error(&my_connection));
            }
        }
        return EXIT_SUCCESS;
    }
下面是编译:
1、gcc -I/usr/include/mysql connect1.c -L/usr/lib/mysql  -L/usr/lib64/mysql  -lmysqlclient -o connect1
我的是这种
2、gcc -I/usr/include/mysql connect1.c -L/usr/lib/mysql  -lmysqlclient -o connect1

返回数据的语句:
你可以使用mysql_query来发送SQL语句,然后,你使用mysql_store_result或者mysql_use_result提取数据。
接着,你将使用一些mysql_fetch_row调用来处理数据。
最后,使用mysql_free_result释放查询占用的内存资源。

mysql_use_result和mysql_store_result的区别主要在于,你想一次返回一行数据,还是一次返回所有的结果。
1、一次提取所有数据的函数
MYSQL_RES *mysql_store_result(MYSQL *connection);

调用mysql_num_rows来得到返回记录的数据,我们希望这是个正数,但是如果没有返回行,这个值将是0:
my_ulonglong mysql_num_rows(MYSQL_RES *result);

a.mysql_fetch_row:这个函数从使用mysql_store_result得到的结构结构中提取一行,并把它放到一个行结构中。当数据用完或者
发生错误时返回NULL
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);

b.mysql_data_seek:这个函数用来在结果集中进行跳转,设置将会被下一个mysql_fetch_row操作返回的行。参数offset的值是一个行号,
它必须在0到结果集总行数减1的范围内。传递0将会导致下一个mysql_fetch_row调用返回结果集中的第一行。
void mysql_data_seek(MYSQL_RES *result,my_ulonglong offset);

c.mysql_row_tell:这个函数返回一个偏移量,它用来表示结果集中的当前位置。
MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES *result);

d.但是,你可以这样使用它的返回值:
MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES *result,MYSQL_ROW_OFFSET offset);

e.完成了对数据的所有操作后,你必须明确的调用mysql_free_result来让MYSQL库完成善后处理:
void mysql_free_result(MYSQL_RES *result);

提取数据试验:
#include 
        #include 

        #include 

        MYSQL my_connection;
        MYSQL_RES *res_ptr;
        MYSQL_ROW sqlrow;

        int main(int argc,char *argv[]){
            int res;

            mysql_init(&my_connection);
            if(mysql_real_connect(&my_connection,"localhost","rick","123456","foo",0,NULL,0)){
                printf("Connection success\n");

                res=mysql_query(&my_connection,"select childno,fname,age from children where age>5");
                if(res){
                    printf("select error: %s\n",mysql_error(&my_connection));
                }
                else{
                    res_ptr=mysql_store_result(&my_connection);
                    if(res_ptr){
                        printf("Retrieved %lu rows\n",(unsigned long)mysql_num_rows(res_ptr));

                        while(sqlrow=mysql_fetch_row(res_ptr)){
                            printf("Fetched data...\n");
                        }
                        if(mysql_errno(&my_connection)){
                            fprintf(stderr,"Retrive error: %s\n",mysql_error(&my_connection));
                        }
                        mysql_free_result(res_ptr);
                    }
                }
                mysql_close(&my_connection);
            }
            else
            {
                fprintf(stderr,"Connection failed\n");
                if(mysql_errno(&my_connection)){
                    fprintf(stderr,"Connection error %d: %s\n",
                        mysql_errno(&my_connection),mysql_error(&my_connection));
                }
            }
            return EXIT_SUCCESS;
        }
编译:
gcc -I/usr/include/mysql insert3.c -L/usr/lib/mysql  -L/usr/lib64/mysql -L/usr/lib/mysql -lmysqlclient -o insert3

一次提取一行数据:
MYSQL_RES *mysql_use_result(MYSQL *connection);

处理返回的数据:
mysql_field_count函数提供了一些关于查询结果的基本信息。它接受连接对象,并返回结果集中的字段数目:
unsigned int mysql_field_count(MYSQL *connection);

下面是简单的打印数据的代码:
void display_row(){
        unsigned int field_count;

        field_count=0;
        while(field_countprintf("%s ",sqlrow(field_count));
            field_count++;
        }
        printf("\n");
    }

使用mysql_fetch_field()来同时将元数据和数据提取到一个新的结构中:
MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result);

#include 
    #include 

    #include 

    MYSQL my_connection;
    MYSQL_RES *res_ptr;
    MYSQL_ROW sqlrow;

    void display_header();
    void display_row();


    int main(int argc, char *argv[]) {
       int res;
       int first_row = 1; /* Used to ensure we display the row header exactly once when data is successfully retrieved */


       mysql_init(&my_connection);  
       if (mysql_real_connect(&my_connection, "localhost", "rick", 
                                                "123456", "foo", 0, NULL, 0)) {
          printf("Connection success\n");

          res = mysql_query(&my_connection, "SELECT childno, fname, age FROM children WHERE age > 5");

          if (res) {
         fprintf(stderr, "SELECT error: %s\n", mysql_error(&my_connection));
          } else {
         res_ptr = mysql_use_result(&my_connection);
         if (res_ptr) {
            while ((sqlrow = mysql_fetch_row(res_ptr))) {
               if (first_row) {
                  display_header();
                  first_row = 0;
               }
               display_row();
            }
            if (mysql_errno(&my_connection)) {
             fprintf(stderr, "Retrive error: %s\n",
                                mysql_error(&my_connection));
            }
            mysql_free_result(res_ptr);
         }
          }
          mysql_close(&my_connection);
       } else {
          fprintf(stderr, "Connection failed\n");
          if (mysql_errno(&my_connection)) {
        fprintf(stderr, "Connection error %d: %s\n",
                                mysql_errno(&my_connection),
                                mysql_error(&my_connection));
        }
          }

       return EXIT_SUCCESS;
    }


    void display_header() {
       MYSQL_FIELD *field_ptr;

       printf("Column details:\n");

       while ((field_ptr = mysql_fetch_field(res_ptr)) != NULL) {
          printf("\t Name: %s\n", field_ptr->name);
          printf("\t Type: ");
          if (IS_NUM(field_ptr->type)) {
         printf("Numeric field\n");
          } else {
         switch(field_ptr->type) {
            case FIELD_TYPE_VAR_STRING:
               printf("VARCHAR\n");
            break;
            case FIELD_TYPE_LONG: 
               printf("LONG\n");
            break;
            default:
              printf("Type is %d, check in mysql_com.h\n", field_ptr->type);
         } /* switch */
          } /* else */

          printf("\t Max width %ld\n", field_ptr->length); /* Note on versions of MySQL before 4.0 the format should be %d, rather than %ld */
          if (field_ptr->flags & AUTO_INCREMENT_FLAG) 
         printf("\t Auto increments\n");
          printf("\n");
       } /* while */
    }


    void display_row() {
       unsigned int field_count;

       field_count = 0;
       while (field_count < mysql_field_count(&my_connection)) {
          if (sqlrow[field_count]) printf("%s ", sqlrow[field_count]);
          else printf("NULL");
          field_count++;
       }
       printf("\n");
    }

更多的函数:
char *mysql_get_client_info(void) 返回客户端使用的库的版本信息
char *mysql_get_host_info(MYSQL *connection) 返回服务器连接信息
char *mysql_get_server_info(MYSQL *connection) 返回当前连接的服务器的信息
char *mysql_info(MYSQL *connection); 返回最近执行的查询的信息,但是仅仅只对一些查询类型有效,通常是insert和updata
int mysql_select_db(MYSQL *connection,const char *dbname)如果用户拥有合适的权限,则把默认数据库改成参数指定的数据库,成功返回0
int mysql_shutdown(MYSQL *connection,enum mysql_enum_shutdown_level); 如果用户拥有合适的权限,则关闭连接的数据库服务器。目前关闭级别必须被设置为SHUTDOWN_DEFAULT.成功时返回0

你可能感兴趣的:(Linux程序设计)