Linux(程序设计):18---C语言访问MySQL(mysql.h)

1、C语言访问MySQL的前提

①安装了MySQL服务端

②安装MySQL库

  • 使用C语言访问MySQL以前须要安装MySQL库,输入如下命令安装:
  1.  
    #环境:Ubuntu 14.04
  2.  
     
  3.  
    sudo apt- get install libmysqlclient-dev

③gcc编译MySQL程序

gcc -I/usr/include/mysql demo.c -L/usr/lib/mysql -lmysqlclient -o demo
 
  • 使用-I添加include路径
  • 使用-L添加库文件路径
  • -lmysqlclient指定连接的库模块
  • 备注:在某些系统上,你可能还须要使用-lz选项来连接压缩库

④mysql头文件

  • 系统中的mysql头文件在/usr/include/mysql/目录下

2、链接句柄初始化(mysql_init)

  1.  
    #include <mysql.h>
  2.  
     
  3.  
    MYSQL *mysql_init(MYSQL *mysql);
  • 功能:用来初始化链接句柄
  • 参数:
    • 若是为NULL,则经过返回值返回一个指向新分配的链接句柄结构的指针
    • 若是传递一个 已有的结构,它将被从新初始化
  • 返回值:出错返回NULL

3、MySQL的链接、断开(mysql_real_connect、mysql_close)

 MySQL的链接

  1.  
    #include <mysql.h>
  2.  
     
  3.  
    MYSQL * mysql_real_connect(MYSQL *mysql,
  4.  
    const char *host,
  5.  
    const char *user,
  6.  
    const char *passwd,
  7.  
    const char *db,
  8.  
    unsigned int port,
  9.  
    const char *unix_socket,
  10.  
    unsigned long clientflag);
  • 功能:用来链接数据库
  • 参数:
    •  mysql:必须指向已经被mysql_init初始化过的结构
    • host:既能够是主机名,也能够是IP地址(若是只是链接到本地机器,你能够经过 指定localhost来优化链接类型)
    • user:登陆用户(若是登陆名为NULL,则假设登陆 名为当前Linux用户的登陆ID)
    • passwd:用户的密码(若是密码为NULL,你将只能访问服务器上无需密码就可访问的数据),密码会在经过网络传输前进行加密
    • db:要访问的数据库
    • port:应该填为0,他们会自动默认使用合适的值(除非你改变了MySQL安装的默认设置)
    • unix_socket:应该填为NULL,他们会自动默认使用合适的值(除非你改变了MySQL安装的默认设置)
    • clientflag:用来对一些定义的位模式进行OR操做,使得改变使用协议的某些特性。通常填0
  • 返回值:
    • 若是出错,返回NULL,mysql_error函数能够提供有帮助的信息

MySQL的断开

  1.  
    #include <mysql.h>
  2.  
     
  3.  
    void mysql_close(MYSQL *sock);
  • 功能:关闭链接
  • 若是链接是由mysql_init创建的,MySQL结构会被释放。指针将会失效并没有法再次使用
  • 保留一个不须要的链接是对资源的浪费,可是从新打开链接也会带来额外的开销,你可使用下面的mysql_options选项函数来权衡选择适合的选项

4、MySQL选项设置(mysql_options)

  1.  
    #include <mysql.h>
  2.  
     
  3.  
    int mysql_options(MYSQL *mysql,enum mysql_option option,const void *arg);
  • 功能:用来设置MySQL链接的一些选项
  • 注意:
    • ①仅能在mysql_init和mysql_real_connect之间调用
    • ②由于mysql_options一次只能设置一个选项,因此每设置一个选项就得调用它一次
  • 参数:
    • mysql:MySQL链接句柄
    • option:设置的选项
    • arg:相对于option选项要设置的值,在使用时须要强制转换为(const char*)
  • option参数以下:
option选项 实际参数类型 说明
MySQL_OPT_CONNECT_TIMEOUT const unsigned int * 链接超时以前的等待秒数
MySQL_OPT_COMPRESS None,使用NULL 网络链接中使用压缩机制
MySQL_INIT_COMMAND const char * 每次链接创建后发送的命令

mysql.h中定义的选项选项:html

  • 返回值:
    • 成功:返回0
    • 失败:返回非0

5、MySQL错误处理(mysql_errno、mysql_error)

  • 由于每次调用库都会更新错误码,因此你只能获得最后一个执行命令的错误码。 可是这两个函数是例外,它们不会致使错误码的更新

返回错误码(mysql_errno)

  1.  
    #include <mysql.h>
  2.  
    #include <mysqld_error.h>
  3.  
    #include <errmsg.h>
  4.  
     
  5.  
    unsigned int mysql_errno(MYSQL *mysql);
  • 功能:传递MySQL句柄,经过返回值返回错误码,错误码一般是非0值
  • 返回值:
    • 若是有错误:错误码经过返回值返回,错误码一般是非0值
    • 若是没有错误:返回值为0
  • 错误码定义头文件文件:
    • /usr/include/mysql/mysqld_error.h:主要定义服务端的错误编码
    • /usr/include/mysql/errmsg.h:主要定义客户端错误

返回错误字符串 (mysql_error)

  1.  
    #include <mysql.h>
  2.  
    #include <mysqld_error.h>
  3.  
    #include <errmsg.h>
  4.  
     
  5.  
    const char * mysql_error(MYSQL *mysql);
  •  功能:传递MySQL句柄,返回错误的文本形式

演示案例

  1.  
    //connect2.c
  2.  
     
  3.  
    #include <stdio.h>
  4.  
    #include <stdlib.h>
  5.  
    #include <mysql.h>
  6.  
    #include <mysqld_error.h>
  7.  
    #include <errmsg.h>
  8.  
     
  9.  
    int main(int argc,char *argv[])
  10.  
    {
  11.  
    MYSQL mysql;
  12.  
    mysql_init(&mysql);
  13.  
     
  14.  
    if(mysql_real_connect(&mysql, "localhost", "root",
  15.  
    "I do not know", "demo", 0, NULL, 0)){
  16.  
    printf( "Connect success\n");
  17.  
    mysql_close(&mysql);
  18.  
    } else{
  19.  
    fprintf( stderr, "Connect failed:\n");
  20.  
    if(mysql_errno(&mysql)){
  21.  
    printf( "\terror code is %d\n\treason:%s\n",mysql_errno(&mysql),mysql_error(&mysql));
  22.  
    }
  23.  
    }
  24.  
     
  25.  
    return 0;
  26.  
    }
  • 编译程序:
gcc -I/usr/include/mysql connect2.c -L/usr/lib/mysql -lmysqlclient -o connect2
 
  • 运行程序:由于上面咱们链接数据库的用户密码错误了,因此打印1045错误编码 ,而且打印了错误字符串

6、执行SQL语句(mysql_query、mysql_real_query)

  • 在编写C语言程序时,SQL语句尽可能不要换行。若是SQL语句过长,不得不换行,能够在行尾使用\字符以容许SQL 语句继续到下一行

mysql_query

  1.  
    #include <mysql.h>
  2.  
     
  3.  
    int mysql_query(MYSQL *mysql, const char *q);
  • 功能:用来执行一条SQL语句(增、删、改、查)
  • 参数:
    • mysql:MySQL句柄
    • q:执行的SQL语句文本字符串,不须要分号
  • 返回值:
    • 执行成功:返回0
    • 执行失败:返回非0

mysql_real_query

  1.  
    #include <mysql.h>
  2.  
     
  3.  
    int mysql_real_query(MYSQL *mysql, const char *q,unsigned long length);
  • 功能:该函数用来查询二进制数据
  • 与mysql_query的区别:mysql_query不能用于二进制数据,该函数能够用于二进制数据查询
  • 返回值:
    • 查询成功返回0
    • 查询成功返回非0

演示案例

  • 由于涉及到博主的数据库的密码,下面咱们的mysql_real_connect函数的数据库密码使用“xxx”表示(出于隐私)
  1.  
    //insert1.c
  2.  
     
  3.  
    #include <stdio.h>
  4.  
    #include <stdlib.h>
  5.  
    #include <mysql.h>
  6.  
    #include <mysqld_error.h>
  7.  
    #include <errmsg.h>
  8.  
     
  9.  
    int main(int argc,char *argv[])
  10.  
    {
  11.  
    MYSQL mysql;
  12.  
    mysql_init(&mysql);
  13.  
     
  14.  
    if(mysql_real_connect(&mysql, "localhost", "root",
  15.  
    "xxx", "demo", 0, NULL, 0)){
  16.  
    printf( "Connect success\n");
  17.  
     
  18.  
    //insert
  19.  
    if(mysql_query(&mysql, "insert into children(fname,age) values('Ann',18)")!= 0){
  20.  
    fprintf( stderr, "mysql_query failed:\n\tcode:%d\n\treason:%s\n",
  21.  
    mysql_errno(&mysql),mysql_error(&mysql));
  22.  
    } else{
  23.  
    printf( "Insert success,affect row are %lu\n",
  24.  
    mysql_affected_rows(&mysql));
  25.  
    }
  26.  
     
  27.  
    mysql_close(&mysql);
  28.  
    } else{
  29.  
    fprintf( stderr, "Connect failed:\n");
  30.  
    if(mysql_errno(&mysql)){
  31.  
    printf( "\terror code is %d\n\treason:%s\n",mysql_errno(&mysql),mysql_error(&mysql));
  32.  
    }
  33.  
    }
  34.  
     
  35.  
    return 0;
  36.  
    }
  • 进入数据库,在demo数据中建立一张表(编号字段自动增长)

  • 编译程序
gcc -I/usr/include/mysql insert1.c -L/usr/lib/mysql -lmysqlclient -o insert1
 
  • 运行程序

  • 查看数据库的信息

7、检查受影响的行数(mysql_affected_rows)

  1.  
    #include <mysql.h>
  2.  
     
  3.  
    my_ulonglong mysql_affected_rows(MYSQL *mysql);
  • 功能:用于检查受查询影响的行数,这个函数返回受以前执行的UPDATE、INSERT或DELETE语句影响的行数
  • 返回值:
    • 返回0:没有行受影响
    • 正数:受影响的行数
  • 返回值类型my_ulonglong:无符号类型,在prinf打印时,强制转换为unsigned long类型,而后使用%lu占位符打印
  • where条件致使的影响行数:在执行一条SQL语句时,若是SQL语句带有where条件,那么虽然有与where匹配的行,当时若是原先的数据与要更改的数据相同,那么这一行就不会被认为更改过了。可是其余数据库语言仅仅由于记录匹 配WHERE子句就把它视为已经更新过(详情见下面的演示案例①)

mysql_real_connect函数的CLIENT_FOUND_ROWS标志

  • 在执行mysql_affected_rows函数时,MySQL会默认省略掉与where匹配可是数据同样的行,从而不会再mysql_affected_rows函数的返回值中记录这一行数。若是在使用mysql_real_connect函数时,将函数的最后一个参数置位CLIENT_FOUND_ROWS,那么即便匹配的那一行数据不用更新也会被记录(详情见下面的演示案例①)

删除数据时的一种特殊状况

  • 在从数据库中删除数据的时候。若是使用WHERE子句删除数据,那么mysql_affected_rows将返回你指望的删除的行数。但若是在DELETE语句中没有WHERE子句(重点:必定要是没有where的删除语句),那么表中的全部行都会被删除,可是由程序返回的受影响行数却为0。 这是由于MySQL优化了删除全部行的操做,它并非执行许多个单行删除操做。这一行为不会受CLIENT_FOUND_ROWS选项标志的影响
  • 这种状况是我在看书时书上说的,可是我在Ubuntu中作了实验,这样特殊状况并不存在,因此究竟是怎么一回事,仍是与实际操做有关

演示案例①

  • 由于涉及到博主的数据库的密码,下面咱们的mysql_real_connect函数的数据库密码使用“xxx”表示(出于隐私)
  1.  
    //update1.c
  2.  
     
  3.  
    #include <stdio.h>
  4.  
    #include <stdlib.h>
  5.  
    #include <mysql.h>
  6.  
    #include <mysqld_error.h>
  7.  
    #include <errmsg.h>
  8.  
     
  9.  
    int main(int argc,char *argv[])
  10.  
    {
  11.  
    MYSQL mysql;
  12.  
    mysql_init(&mysql);
  13.  
     
  14.  
    if(mysql_real_connect(&mysql, "localhost", "root",
  15.  
    "xxx", "demo", 0, NULL, 0)){
  16.  
    printf( "Connect success\n");
  17.  
     
  18.  
    //insert
  19.  
    if(mysql_query(&mysql, "update children set age=20 where fname='Ann'")!= 0){
  20.  
    fprintf( stderr, "mysql_query failed:\n\tcode:%d\n\treason:%s\n",
  21.  
    mysql_errno(&mysql),mysql_error(&mysql));
  22.  
    } else{
  23.  
    printf( "Update success,affect row are %lu\n",
  24.  
    mysql_affected_rows(&mysql));
  25.  
    }
  26.  
     
  27.  
    mysql_close(&mysql);
  28.  
    } else{
  29.  
    fprintf( stderr, "Connect failed:\n");
  30.  
    if(mysql_errno(&mysql)){
  31.  
    printf( "\terror code is %d\n\treason:%s\n",mysql_errno(&mysql),mysql_error(&mysql));
  32.  
    }
  33.  
    }
  34.  
     
  35.  
    return 0;
  36.  
    }
  • 运行程序前,查看数据库,名为Ann的行数,有2行age为18,有2行age为20

  • 编译程序:
gcc -I/usr/include/mysql update1.c -L/usr/lib/mysql -lmysqlclient -o update1
 
  • 运行程序:
    • 能够看到数据库中名为Ann的行有4行,可是更新以后受影响的行数只有2行,由于另外两行虽然与SQL语句匹配,可是因为其qge已经为20了,就没有更新,所以也就没有被认为被影响

  • 咱们复制上面的updae1.c程序,并新建一个update2.c程序,将mysql_real_connect函数的最后一个参数设置为CLIENT_FOUND_ROWS

  • 更改数据库,更改age字段为原先的两行18,两行20

  • 编译程序:
gcc -I/usr/include/mysql update2.c -L/usr/lib/mysql -lmysqlclient -o update2
 
  • 运行程序:
    • 能够看到mysql_real_connect函数加上了CLIENT_FOUND_ROWS标志以后,即便有的行数没有更改数据,可是那2行被where条件匹配了,也就算在了影响的行数中

8、MySQL的last_insert_id函数

  • 注意:last_inser_id是MySQL数据库中的一个函数,而不是C语言提供的API

last_inser_id函数应用的场景

  • 插入数据有一个微小但相当重要的方面。MySQL表中的数据类型为AUTO_INCREMENT的字段,它由MySQL自动分配ID。这一特性很是有用,特别是当你有许多用户的时候
  • 例如在上面咱们定义的children时,将childno字段类型设置为AUTO_INCREMENT

  • 正如你看到的那样,childno列被设为AUTO_INCREMENT类型。这样固然很好,可是一旦你插入一 行,你如何知道刚插入的孩子被分配了什么数字呢?
  • 你能够执行一条SELECT语句来搜索孩子的名字,但这样效率会很低,而且若是有两个相同名字的 孩子,这将不能保证惟一性。或者,若是同时有多个用户快速地插入数据,那么可能在更新操做和 SELECT语句之间会有其余行被插入。由于发现一个AUTO_INCREMENT列的值是你们都面临的一个共同 问题,因此MySQL以函数LAST_INSERT_ID()的形式提供了一个专门的解决方案
  • 不管什么时候MySQL向AUTO_INCREMENT列中插入数据,MySQL都会基于每一个用户对最后分配的值进 行跟踪。用户程序能够经过SELECT专用函数LAST_INSERT_ID()来发现该值,这个函数的做用有点像 是表中的虚拟列

MySQL操做演示案例

  • 先查看表中没有任何数据

  • 此时插入一条语句,并查看last_insert_id函数的返回值

  • 此时再插入一条语句,并查看last_insert_id函数的返回值

  • 查看数据库信息,能够看到插入的childno的值与咱们的last_insert_id函数返回的值同样

  • 实验解析:每次插入一行,MySQL就分配一个新的id值而且跟踪它,使得你能够用LAST_INSERT_ID()来提取它

若是想经过实验查看返回的数字在本次会话中确实是惟一的,那么你能够打开另外一个会话并插入 另外一行数据。而后在最初的会话中从新执行SELECT LAST_INSERT_ID();语句。你将看到数字并无 发生改变,这是由于该语句返回的数字是由当前会话插入的最后一个数字。可是,若是执行SELECT * FROM children,你将看到其余会话确实已插入数据了mysql

  • 此时,咱们再新建一个新的会话窗口(与先前的不是同一个会话),而且使用LAST_INSERT_ID()返回插入的ID值,能够看到为15

  • 此时,咱们来到第一个会话窗口执行LAST_INSERT_ID()函数,发现其值仍是14。而后查询表数据,能够看到另外一个会话插入的数据已经插入了(由此能够得出LAST_INSERT_ID()函数返回的数字在本次会话中是惟一的)

C语言演示案例

  • 由于涉及到博主的数据库的密码,下面咱们的mysql_real_connect函数的数据库密码使用“xxx”表示(出于隐私)
  1.  
    //insert2.c
  2.  
     
  3.  
    #include <stdio.h>
  4.  
    #include <stdlib.h>
  5.  
    #include <mysql.h>
  6.  
    #include <mysqld_error.h>
  7.  
    #include <errmsg.h>
  8.  
     
  9.  
    int main(int argc,char *argv[])
  10.  
    {
  11.  
    MYSQL mysql;
  12.  
    MYSQL_RES *res_ptr;
  13.  
    MYSQL_ROW sqlrow;
  14.  
     
  15.  
    mysql_init(&mysql);
  16.  
     
  17.  
    if(mysql_real_connect(&mysql, "localhost", "root",
  18.  
    "xxx", "demo", 0, NULL, 0)){
  19.  
    printf( "Connect success\n");
  20.  
     
  21.  
    //insert
  22.  
    if(mysql_query(&mysql, "insert into children(fname,age) values('Robert',7)")!= 0){
  23.  
    fprintf( stderr, "mysql_query failed:\n\tcode:%d\n\treason:%s\n",
  24.  
    mysql_errno(&mysql),mysql_error(&mysql));
  25.  
    } else{
  26.  
    printf( "Insert %lu rows\n",( unsigned long)mysql_affected_rows(&mysql));
  27.  
    }
  28.  
     
  29.  
    //select last_insert_id()
  30.  
    if(mysql_query(&mysql, "select last_insert_id()")!= 0){
  31.  
    fprintf( stderr, "mysql_query failed:\n\tcode:%d\n\treason:%s\n",
  32.  
    mysql_errno(&mysql),mysql_error(&mysql));
  33.  
    } else{
  34.  
    res_ptr=mysql_use_result(&mysql)
  35.  
    if(res_ptr){
  36.  
    while((sqlrow=mysql_fetch_row(res_ptr))){
  37.  
    printf( "We inserted childno %s\n",sqlrow[ 0]);
  38.  
    }
  39.  
    mysql_free_result(res_ptr);
  40.  
    }
  41.  
    }
  42.  
     
  43.  
    mysql_close(&mysql);
  44.  
    } else{
  45.  
    fprintf( stderr, "Connect failed:\n");
  46.  
    if(mysql_errno(&mysql)){
  47.  
    printf( "\terror code is %d\n\treason:%s\n",mysql_errno(&mysql),mysql_error(&mysql));
  48.  
    }
  49.  
    }
  50.  
     
  51.  
    return 0;
  52.  
    }
  53.  
     
  • 编译程序:
gcc -I/usr/include/mysql insert2.c -L/usr/lib/mysql -lmysqlclient -o insert2
 
  • 运行程序:在插入一行以后,你用LAST_INSERT_ID()函数来获取分配的ID,就像常规的SELECT语句同样。 而后使用mysql_use_result()从执行的SELECT语句中获取数据并将它打印出来,咱们稍后将解释此函数

9、MySQL查询:一次提取全部数据(mysql_store_result)

在C应用程序中提取数据通常须要下面4个步骤:

  • 执行查询(mysql_query)
  • 提取数据(mysql_store_result或mysql_use_result)
  • 处理数据(mysql_fetch_row)
  • 必要的清理工做(mysql_free_result)

MYSQL_RES、MYSQL_ROW、MYSQL_ROW_OFFSET数据类型

  • MYSQL_RES:表明从SELECT(或其余返回数据的语句)中提取全部数据,是一个结果集结构
  • MYSQL_ROW:表明MYSQL_RES数据集中的一行,是一个行结构
    • 下标操做,由于MYSQL_ROW表明一行数据,咱们可使用索引的方式取出一行中的对应下标数据,例如MYSQL_ROW row,row[0]、row[1]、row[2]
  • MYSQL_ROW_OFFSET:表明当前程序在MYSQL_RES结果集中所操做的行索引

mysql_store_result:一次提取全部数据

  1.  
    #include <mysql.h>
  2.  
     
  3.  
    MYSQL_RES *mysql_store_result(MYSQL *mysql);
  • 功能:mysql_store_result在一次调用中从SELECT(或其余返回数据的语句)中提取全部数据
  • 参数:MySQL的链接句柄
  • 返回值:
    • 成功:保存查询到的结果集结构指针
    • 失败:NULL
  • 返回值的注意事项:提示没有提取到数据,这个函数仍是返回一个MYSQL_RES指针,而不是NULL,NULL只有在函数出错时返回。所以在编程时判断该函数出错的条件应该是该函数返回NULL
  • mysql_use_result是一次只从结果中提取一行数据,置于二者的区别,咱们在下面介绍mysql_use_result函数时会讲解

mysql_num_rows:获取返回的行数

  1.  
    #include <mysql.h>
  2.  
     
  3.  
    my_ulonglong mysql_num_rows(MYSQL_RES *result);
  • 功能:函数参数为mysql_store_result返回的结果集结构(MYSQL_RES),返回结果集中的行数
  • 返回值:
    • 正数:为返回的行数。在prinf打印时,强制转换为unsigned long类型,而后使用%lu占位符打印
    • 0:没有返回行数
  • 若是mysql_store_ result调用成功,mysql_num_rows将始终都是成功的

mysql_fetch_row:提取一行

  1.  
    #include <mysql.h>
  2.  
     
  3.  
    MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
  • 功能:从mysql_store_result获得的结果集结构(MYSQL_RES)中提取一行,并把它放到一个行结构中
  • 返回值:
    • 成功:返回一个行结构(MYSQL_ROW)
    • 数据用完或失败:返回NULL
  • 这个函数每次只能从MYSQL_RES中提取一行,所以想要提取全部行,须要不断的调用该函数

mysql_data_seek、mysql_row_tell、mysql_row_seek:行数索引操做

  1.  
    #include <mysql.h>
  2.  
     
  3.  
    void mysql_data_seek(MYSQL_RES *result,my_ulonglong offset);
  4.  
     
  5.  
    MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES *res);
  6.  
     
  7.  
    MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES *result,MYSQL_ROW_OFFSET offset);
  • mysql_data_seek:这个函数用来在结果集中进行跳转,设置了offset以后,下一次mysql_fetch_row读取的行就是这个函数所设置的行
    • 参数result:结果集
    • 参数offset:行号,必须在0到结果集总行数减1的范围内。传递0会致使下一个mysql_fetch_row调用返回结果集中的第一行
  • mysql_row_tell:这个函数返回一个偏移值,它用来表示结果集中的当前位置。但返回值不是行号,而是一种MYSQL_ROW_OFFSET数据类型
  • mysql_row_seek:该函数用于将当前的位置移动到参数offset所指的位置(不是行号,是MYSQL_ROW_OFFSET类型),函数的返回值是该函数执行以前的位置(重点)

备注:sql

  • 不要把mysql_data_seek函数和mysql_row_tell、mysql_row_seek函数所操做的行数混淆,前者是整型,后二者是MYSQL_ROW_OFFSET数据类型

mysql_free_result:清除操做/善后处理

  1.  
    #include <mysql.h>
  2.  
     
  3.  
    void mysql_free_result(MYSQL_RES *result);
  • 功能:完成了对结果集的操做后,你必须老是调用此函数来让MySQL库清理它分配的对象
  • 完成了对数据的全部操做后,你必须明确地调用mysql_free_result来让MySQL库完成善后处理

演示案例

  • 由于涉及到博主的数据库的密码,下面咱们的mysql_real_connect函数的数据库密码使用“xxx”表示(出于隐私)
  • 下面的程序只是简单的获取返回的行数有多少行,而没有对返回的数据进行操做,对数据进行操做将在下面的演示案例中讲解
  1.  
    //select1.c
  2.  
     
  3.  
    #include <stdio.h>
  4.  
    #include <stdlib.h>
  5.  
    #include <mysql.h>
  6.  
    #include <mysqld_error.h>
  7.  
    #include <errmsg.h>
  8.  
     
  9.  
    int main(int argc,char *argv[])
  10.  
    {
  11.  
    MYSQL mysql;
  12.  
    MYSQL_RES *res;
  13.  
    MYSQL_ROW sqlrow;
  14.  
     
  15.  
    mysql_init(&mysql);
  16.  
     
  17.  
    if(mysql_real_connect(&mysql, "localhost", "root",
  18.  
    "xxx", "demo", 0, NULL, 0)){
  19.  
    printf( "Connect success\n");
  20.  
     
  21.  
    //select
  22.  
    if(mysql_query(&mysql, "select childno,fname,age from children where age>5")!= 0){
  23.  
    fprintf( stderr, "mysql_query failed:\n\tcode:%d\n\treason:%s\n",
  24.  
    mysql_errno(&mysql),mysql_error(&mysql));
  25.  
    } else{
  26.  
    //get result
  27.  
    res=mysql_store_result(&mysql);
  28.  
    if(res!= NULL){
  29.  
    //show rows
  30.  
    printf( "Retrived %lu rows:\n",( unsigned long)mysql_num_rows(res));
  31.  
    //Get one row at a time
  32.  
    while(sqlrow=mysql_fetch_row(res)){
  33.  
    printf( "\tFetch row...\n");
  34.  
    }
  35.  
    } else{
  36.  
    if(mysql_errno(&mysql)){
  37.  
    printf( "\terror code is %d\n\treason:%s\n",
  38.  
    mysql_errno(&mysql),mysql_error(&mysql));
  39.  
    }
  40.  
    }
  41.  
    }
  42.  
     
  43.  
    mysql_close(&mysql);
  44.  
    } else{
  45.  
    fprintf( stderr, "Connect failed:\n");
  46.  
    if(mysql_errno(&mysql)){
  47.  
    printf( "\terror code is %d\n\treason:%s\n",
  48.  
    mysql_errno(&mysql),mysql_error(&mysql));
  49.  
    }
  50.  
    }
  51.  
     
  52.  
    return 0;
  53.  
    }
  • 查看数据库信息(能够看到age>5的有3条记录):

  • 编译程序:
gcc -I/usr/include/mysql select1.c -L/usr/lib/mysql -lmysqlclient -o select1
 
  • 运行程序:

10、MySQL查询:一次提取一行数据(mysql_use_result)

  1.  
    #include <mysql.h>
  2.  
     
  3.  
    MYSQL_RES *mysql_use_result(MYSQL *mysql);
  • 功能:逐行提取数据
  • 返回值:
    • 正确:与mysql_store_result同样,保存查询到的结果集结构指针
    • 失败:返回NULL

工做原理

  • 这个函数在执行以后,其返回值MYSQL_RES是空的,也就是说其未将提取的数据放到它初始化的结果集中
  • 接着,会在mysql_use_result函数以后调用mysql_fetch_row函数,并将mysql_use_result函数的返回值做为mysql_fetch_row函数的参数,而后使用while循环执行mysql_fetch_row函数,mysql_fetch_row函数会每执行一次才从网络中获取一行数据
  • 所以,咱们所说的一次提取一行数据并非发生在mysql_use_result函数提取一行,而是在后面调用mysql_fetch_row函数时才正真的一次只提取一行(重点)
  • 因此,想要得到多少行数据,就调用多少次mysql_fetch_row函数,其调用次数与获取的行数是1:1的关系。想要获取全部数据,就是while循环不断执行mysql_fetch_row函数

mysql_num_rows函数的注意事项

  • 在没有调用mysql_fetch_row以前,mysql_num_rows老是返回0,所以此时程序尚未正确的获取数据
  • 每当调用一次mysql_fetch_row,mysql_num_rows函数所获取的行数就会加1,所以调用mysql_fetch_row以后,此时程序中就被认为获取了一行数据

与mysql_store_result到底有什么区别:

  • 对于mysql_store_resul来讲,其一次性直接获取全部的查询数据,而且查询的数据时保存在本地的,使用这个函数能够不用担忧网络或远程数据库错误带来数据丢失的影响
  • 对于mysql_use_result来讲,其备资源管理方面的实质性好处(更好地平衡了网络负载,以及 减小了可能很是大的数据集带来的存储开销),可是它不能与mysql_data_seek、mysql_row_seek或mysql_row_tell一块儿使用,而且因为直到全部数据都被提取后才能实际生效,mysql_num_rows的使用也受到限制(见下面演示案例)
  • 若是你碰巧使用的是一个特别庞大的数据集,那么最好使用mysql_use_result函数提取小一些、更容易管理的信息块,由于这将更快地将控制权返回给应用程序,而且不会占用大量的网络资源

演示案例

  • 由于涉及到博主的数据库的密码,下面咱们的mysql_real_connect函数的数据库密码使用“xxx”表示(出于隐私)
  1.  
    //select2.c
  2.  
     
  3.  
    #include <stdio.h>
  4.  
    #include <stdlib.h>
  5.  
    #include <mysql.h>
  6.  
    #include <mysqld_error.h>
  7.  
    #include <errmsg.h>
  8.  
     
  9.  
    int main(int argc,char *argv[])
  10.  
    {
  11.  
    MYSQL mysql;
  12.  
    MYSQL_RES *res;
  13.  
    MYSQL_ROW sqlrow;
  14.  
     
  15.  
    mysql_init(&mysql);
  16.  
     
  17.  
    if(mysql_real_connect(&mysql, "localhost", "root",
  18.  
    "xxx", "demo", 0, NULL, 0)){
  19.  
    printf( "Connect success\n");
  20.  
     
  21.  
    //select
  22.  
    if(mysql_query(&mysql, "select childno,fname,age from children where age>5")!= 0){
  23.  
    fprintf( stderr, "mysql_query failed:\n\tcode:%d\n\treason:%s\n",
  24.  
    mysql_errno(&mysql),mysql_error(&mysql));
  25.  
    } else{
  26.  
    //get result
  27.  
    res=mysql_use_result(&mysql);
  28.  
    if(res!= NULL){
  29.  
    //Get one row at a time
  30.  
    while(sqlrow=mysql_fetch_row(res)){
  31.  
    printf( "\tFetch row...\n");
  32.  
    }
  33.  
    } else{
  34.  
    if(mysql_errno(&mysql)){
  35.  
    printf( "\terror code is %d\n\treason:%s\n",
  36.  
    mysql_errno(&mysql),mysql_error(&mysql));
  37.  
    }
  38.  
    }
  39.  
    }
  40.  
     
  41.  
    mysql_close(&mysql);
  42.  
    } else{
  43.  
    fprintf( stderr, "Connect failed:\n");
  44.  
    if(mysql_errno(&mysql)){
  45.  
    printf( "\terror code is %d\n\treason:%s\n",
  46.  
    mysql_errno(&mysql),mysql_error(&mysql));
  47.  
    }
  48.  
    }
  49.  
     
  50.  
    return 0;
  51.  
    }
  • 查看数据库:

  • 编译程序:
gcc -I/usr/include/mysql select2.c -L/usr/lib/mysql -lmysqlclient -o select2
 
  • 运行结果:由于mysql_num_rows放置到了mysql_fetch_row函数的前面,此时程序尚未正真的从数据库中获取数据,所以mysql_num_rows函数显示为0

  • 如今咱们更改程序:复制select2.c,新建select3.c程序将程序中的mysql_num_rows函数放置到mysql_fetch_row循环中

  • 运行select3.c结果:能够看到每次调用mysql_fetch_row获取一行数据以后,mysql_num_rows函数再去执行就能够获取到行数了

11、获得返回的列(字段)数(mysql_field_count)

  • 在上面咱们介绍了如何提取行,下面学习如何处理返回的数据了。如同大多数SQL数据库同样,MySQL返回两种类型的数据:
    • 列数据:从表中提取的信息
    • 元数据:关于数据的数据,例如列名和类型
  1.  
    #include <mysql.h>
  2.  
     
  3.  
    unsigned int mysql_field_count(MYSQL *mysql);
  • 功能:提供了一些关于查询结果的基本信息,它接受链接对象,并返回结果集中的字段(列)数目
  • 参数:链接的mysql对象
  • 返回值:字段(列)数目

使用mysql_field_count判断mysql_store_result的调用失败缘由

  • mysql_field_count提供一个功能:判断为什么mysql_ store_result的调用会失败
  • 例如,若是mysql_store_result返回NULL,可是mysql_field_ count 返回一个正数,你能够推测这是一个提取错误。可是,若是mysql_field_count返回0,则表示没有 列能够提取,这能够解释为什么存储结果会失败

演示案例

  • 由于涉及到博主的数据库的密码,下面咱们的mysql_real_connect函数的数据库密码使用“xxx”表示(出于隐私)
  1.  
    //insert4.c
  2.  
     
  3.  
    #include <stdio.h>
  4.  
    #include <stdlib.h>
  5.  
    #include <mysql.h>
  6.  
    #include <mysqld_error.h>
  7.  
    #include <errmsg.h>
  8.  
     
  9.  
    void display_show(MYSQL *mysql,MYSQL_ROW *sqlrow);
  10.  
     
  11.  
    int main(int argc,char *argv[])
  12.  
    {
  13.  
    MYSQL mysql;
  14.  
    MYSQL_RES *res;
  15.  
    MYSQL_ROW sqlrow;
  16.  
     
  17.  
    mysql_init(&mysql);
  18.  
     
  19.  
    if(mysql_real_connect(&mysql, "localhost", "root",
  20.  
    "xxx", "demo", 0, NULL, 0)){
  21.  
    printf( "Connect success\n");
  22.  
     
  23.  
    //select
  24.  
    if(mysql_query(&mysql, "select childno,fname,age from children where age>5")!= 0){
  25.  
    fprintf( stderr, "mysql_query failed:\n\tcode:%d\n\treason:%s\n",
  26.  
    mysql_errno(&mysql),mysql_error(&mysql));
  27.  
    } else{
  28.  
    //get result
  29.  
    res=mysql_use_result(&mysql);
  30.  
    if(res!= NULL){
  31.  
    //Get one row at a time
  32.  
    while(sqlrow=mysql_fetch_row(res)){
  33.  
    printf( "Fetch row:\n");
  34.  
    display_show(&mysql,&sqlrow);
  35.  
    }
  36.  
    } else{
  37.  
    if(mysql_errno(&mysql)){
  38.  
    printf( "\terror code is %d\n\treason:%s\n",
  39.  
    mysql_errno(&mysql),mysql_error(&mysql));
  40.  
    }
  41.  
    }
  42.  
    }
  43.  
     
  44.  
    mysql_close(&mysql);
  45.  
    } else{
  46.  
    fprintf( stderr, "Connect failed:\n");
  47.  
    if(mysql_errno(&mysql)){
  48.  
    printf( "\terror code is %d\n\treason:%s\n",
  49.  
    mysql_errno(&mysql),mysql_error(&mysql));
  50.  
    }
  51.  
    }
  52.  
     
  53.  
    return 0;
  54.  
    }
  55.  
     
  56.  
    void display_show(MYSQL *mysql,MYSQL_ROW *sqlrow)
  57.  
    {
  58.  
    unsigned int count= 0;
  59.  
    while(count<mysql_field_count(mysql)){
  60.  
    printf( "\t%s",(*sqlrow)[count]);
  61.  
    count++;
  62.  
    }
  63.  
    printf( "\n");
  64.  
    }
  • 查看数据库:

  • 编译程序:
gcc -I/usr/include/mysql select4.c -L/usr/lib/mysql -lmysqlclient -o select4
 
  • 运行结果:由于查询的结果集中有3个字段,所以mysql_field_count函数返回3,在display_show函数中咱们用while循环遍历,由于sqlrow表明一行数据,接着咱们用索引一次取出一行中的0、一、2下标的数据,也就是childno、fname、age

11、得到字段属性(mysql_fetch_field)

  1.  
    #include <mysql.h>
  2.  
     
  3.  
    MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result);
  • 上面咱们使用mysql_field_count函数虽然也能够打印数据,可是输出不美观,而且每回都返回一行数据,并且查询的结果中能够能会出现NULL。若是想要打印出更整洁的格式化(或许是表格化)的数据,你须要同时获得MySQL返回的数据和元数据。你可使用mysql_fetch_field函数来同时将元数据和数据提取到一个新的结构中
  • 参数:查询返回的结果集
  • 返回值:
    • 成功:返回一个MYSQL_FIELD的结构
    • 数据读取完或失败:返回NULL

MYSQL_FIELD的结构

  • 一个字段就用一个MYSQL_FIELD结构体标识,该结构体能够表示字段的数据类型、字段名、所属表等信息
  1.  
    typedef struct st_mysql_field {
  2.  
    char *name; /* Name of column */
  3.  
    char *org_name; /* Original column name, if an alias */
  4.  
    char *table; /* Table of column if column was a field */
  5.  
    char *org_table; /* Org table name, if table was an alias */
  6.  
    char *db; /* Database for table */
  7.  
    char *catalog; /* Catalog for table */
  8.  
    char *def; /* Default value (set by mysql_list_fields) */
  9.  
    unsigned long length; /* Width of column (create length) */
  10.  
    unsigned long max_length; /* Max width for selected set */
  11.  
    unsigned int name_length;
  12.  
    unsigned int org_name_length;
  13.  
    unsigned int table_length;
  14.  
    unsigned int org_table_length;
  15.  
    unsigned int db_length;
  16.  
    unsigned int catalog_length;
  17.  
    unsigned int def_length;
  18.  
    unsigned int flags; /* Div flags */
  19.  
    unsigned int decimals; /* Number of decimals in field */
  20.  
    unsigned int charsetnr; /* Character set */
  21.  
    enum enum_field_types type; /* Type of field. See mysql_com.h for types */
  22.  
    void *extension;
  23.  
    } MYSQL_FIELD;

比较重要的成员数据库

  • char *name:列名,为字符串
  • char *table:列所属的表名。当一个查询要使用到多个表时,这将特别有用。注意: 对于结果中可计算的值如MAX,它所对应的表名将为空字符串
  • char *def:若是调用mysql_list_fields(咱们未在这里介绍它),它将包含该列 的默认值
  • enum enum_field_types type:列类型,至关普遍,列类型在头文件mysql_con.h头文件中,常见的几种以下
    • FIELD_TYPE_DECIMAL
    • FIELD_TYPE_LONG
    • FIELD_TYPE_STRING
    • FIELD_TYPE_VAR_STRING
  • 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。完整列表可参见MySQL文档。能够在编程时利用flags成员与这些值进行“&”而后某一字段是否属于某一标志
  • unsigned int decimals:小数点后的数字个数。仅对数字字段有效

IS_NUM宏

  1.  
    #include <mysql.h>
  2.  
     
  3.  
    #define IS_NUM(t) (((t) <= MYSQL_TYPE_INT24 && (t) != MYSQL_TYPE_TIMESTAMP) || (t) == MYSQL_TYPE_YEAR || (t) == MYSQL_TYPE_NEWDECIMAL)
  •  功能:当字段类型为数字时,它返回true
  1.  
    //演示案例
  2.  
    if(IS_NUM(mysql_filed_prt->type))
  3.  
    printf( "Number type field\n");

mysql_field_seek函数

  1.  
    #include <mysql.h>
  2.  
     
  3.  
    MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *result,MYSQL_FIELD_OFFSET offset);
  • 设置当前的字段编号
  • 该编号会随每次mysql_fetch_field调用而自动增长
  • 若是给参数offset传递值0,你将跳回第一列

演示案例

  • 由于涉及到博主的数据库的密码,下面咱们的mysql_real_connect函数的数据库密码使用“xxx”表示(出于隐私)
  1.  
    //select5.c
  2.  
     
  3.  
    #include <stdio.h>
  4.  
    #include <stdlib.h>
  5.  
    #include <mysql.h>
  6.  
    #include <mysqld_error.h>
  7.  
    #include <errmsg.h>
  8.  
     
  9.  
    void display_header(MYSQL_RES *result);
  10.  
    void display_show(MYSQL *mysql,MYSQL_ROW *sqlrow);
  11.  
     
  12.  
    int main(int argc,char *argv[])
  13.  
    {
  14.  
    int isHeader;
  15.  
    MYSQL mysql;
  16.  
    MYSQL_RES *res;
  17.  
    MYSQL_ROW sqlrow;
  18.  
    isHeader= 1;
  19.  
     
  20.  
    mysql_init(&mysql);
  21.  
     
  22.  
    if(mysql_real_connect(&mysql, "localhost", "root",
  23.  
    "xxx", "demo", 0, NULL, 0)){
  24.  
    printf( "Connect success\n");
  25.  
     
  26.  
    //select
  27.  
    if(mysql_query(&mysql, "select childno,fname,age from children where age>5")!= 0){
  28.  
    fprintf( stderr, "mysql_query failed:\n\tcode:%d\n\treason:%s\n",
  29.  
    mysql_errno(&mysql),mysql_error(&mysql));
  30.  
    } else{
  31.  
    //get result
  32.  
    res=mysql_use_result(&mysql);
  33.  
    if(res!= NULL){
  34.  
    //Get one row at a time
  35.  
    while(sqlrow=mysql_fetch_row(res)){
  36.  
    if(isHeader){
  37.  
    display_header(res);
  38.  
    isHeader= 0;
  39.  
    printf( "Row Deails:\n");
  40.  
    }
  41.  
    display_show(&mysql,&sqlrow);
  42.  
    }
  43.  
    } else{
  44.  
    if(mysql_errno(&mysql)){
  45.  
    printf( "\terror code is %d\n\treason:%s\n",
  46.  
    mysql_errno(&mysql),mysql_error(&mysql));
  47.  
    }
  48.  
    }
  49.  
    }
  50.  
    mysql_close(&mysql);
  51.  
    } else{
  52.  
    fprintf( stderr, "Connect failed:\n");
  53.  
    if(mysql_errno(&mysql)){
  54.  
    printf( "\terror code is %d\n\treason:%s\n",
  55.  
    mysql_errno(&mysql),mysql_error(&mysql));
  56.  
    }
  57.  
    }
  58.  
     
  59.  
    return 0;
  60.  
    }
  61.  
     
  62.  
     
  63.  
    void display_header(MYSQL_RES *result)
  64.  
    {
  65.  
    printf( "Column Details:\n");
  66.  
    MYSQL_FIELD *field;
  67.  
    //循环,每次返回一个字段
  68.  
    while((field=mysql_fetch_field(result))!= NULL){
  69.  
    //1
  70.  
    printf( "\tcol_name:%s",field->name);
  71.  
    //2
  72.  
    if(IS_NUM(field->type)){
  73.  
    printf( " ,type:%s", "Number");
  74.  
    } else{
  75.  
    switch(field->type){
  76.  
    case FIELD_TYPE_DECIMAL:
  77.  
    printf( " ,type:%s", "Decimal");
  78.  
    break;
  79.  
    case FIELD_TYPE_LONG:
  80.  
    printf( " ,type:%s", "Long");
  81.  
    break;
  82.  
    case FIELD_TYPE_STRING:
  83.  
    printf( " ,type:%s", "String");
  84.  
    break;
  85.  
    case FIELD_TYPE_VAR_STRING:
  86.  
    printf( " ,type:%s", "Var_String");
  87.  
    break;
  88.  
    }
  89.  
    }
  90.  
    //3
  91.  
    printf( " ,column width:%ld",field->length);
  92.  
    //4
  93.  
    if(field->flags & AUTO_INCREMENT_FLAG){
  94.  
    printf(
  95.  
    " ,column flags:%s", "AUTO_INCREMENT_ FLAG");
  96.  
    }
  97.  
    printf( "\n");
  98.  
    }
  99.  
    }
  100.  
     
  101.  
    void display_show(MYSQL *mysql,MYSQL_ROW *sqlrow)
  102.  
    {
  103.  
    unsigned int count= 0;
  104.  
    while(count<mysql_field_count(mysql)){
  105.  
    if((*sqlrow)[count]){
  106.  
    printf( "\t%s",(*sqlrow)[count]);
  107.  
    } else{
  108.  
    printf( "NULL");
  109.  
    }
  110.  
    count++;
  111.  
    }
  112.  
    printf( "\n");
  113.  
    }
  •  查看数据库:

 

  • 编译程序:
gcc -I/usr/include/mysql select5.c -L/usr/lib/mysql -lmysqlclient -o select5
 
  • 运行程序: 

12、更多的函数

  • 下表中显示了其余一些其余经常使用的API函数
示例API调用 说 明
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和UPDATE语句,不然返回 NULL
int mysql_select_db(MySQL *connection, const char *dbname); 若是用户拥有合适的权限,则把默认数据库改成参数 指定的数据库。成功时返回0
int mysql_shutdown(MySQL *connection,enum mysql_enum_shutdown_level); 若是用户拥有合适的权限,则关闭链接的数据库服务 器。目前关闭级别必须被设置为SHUTDOWN_DEFAULT。成 功时返回0
相关文章
相关标签/搜索