分享

使用C语言访问MySQL数据 —— 执行SQL语句(2)

 Fredanf 2012-12-01

使用C语言访问MySQL数据 —— 执行SQL语句(2)

分类: GNU/Linux MySQL C/C++ 402人阅读 评论(0) 收藏 举报

2011-05-15 wcdj

 

(一) 不返回数据的SQL语句 —— UPDATE、DELETE 和 INSERT
(二) 发现插入的内容
(三) 返回数据的语句
(1) 一次提取所有数据的函数
(2) 一次提取一行数据的函数



(三) 返回数据的语句
SQL最常见的用法当然是提取数据而不是插入或更新数据。数据是使用SELECT语句提取的。
说明 :MySQL也支持使用SQL语句SHOW、DESCRIBE和EXPLAIN来返回结果,但我们不会在这里涉及它们。按照惯例,手册中包含了对这些语句的解释。

在C应用程序中提取数据一般需要下面4个步骤
【1】执行查询
【2】提取数据
【3】处理数据
【4】必要的清理工作
使用mysql_query来发送SQL语句,然后使用mysql_store_result或mysql_use_result来提取数据,接着,使用一些列mysql_fetch_row调用来处理数据。最后,使用mysql_free_result释放查询占用的内存资源。
说明 :mysql_use_result和mysql_store_result的区别 :主要在于,你是想一次返回一行数据,还是一次返回所有的结果。当你预计结果集比较小时,后者会更加合适。

(1) 一次提取所有数据的函数
可以使用mysql_store_result在一次调用中从SELECT(或其他返回数据的语句)中提取所有数据:
MYSQL_RES *mysql_store_result( MYSQL *connection );
你需要在成功调用mysql_query之后使用此函数。这个函数将立刻保存在客户端中返回的所有数据。它返回一个指向结果集结构的指针,如果失败则返回NULL。
在mysql_store_result调用成功之后,你需要调用mysql_num_rows来得到返回记录的数目,我们希望这是个正数,但是如果没有返回行,这个值将是0。
my_ulonglong mysql_num_rows( MYSQL_RES *result );
这个函数接受由mysql_store_result返回的结果结构,并返回结果集中的行数。如果mysql_store_result调用成功,mysql_num_rows将始终都是成功的。

注意
如果碰巧使用的是一个特别 的数据集,那么最后提取小一些、更容易管理的信息块,因为这将更快地将控制权返回给应用程序,并且不会占用大量的网络资源。具体参考mysql_use_result的用法。

现在,你可以使用mysql_fetch_row来处理它,也可以使用mysql_data_seek、mysql_row_seek和mysql_row_tell在数据集中来回移动。

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

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

[3] mysql_row_tell
这个函数返回一个偏移值,它用来表示结果集中的当前位置。它不是行号,你不能把它用于mysql_data_seek。
MYSQL_ROW_OFFSET mysql_row_tell( MYSQL_RES *result );

[4] mysql_row_seek
可以在mysql_row_seek中使用mysql_row_tell的返回值。
MYSQL_ROW_OFFSET mysql_row_seek( MYSQL_RES *result, MYSQL_ROW_OFFSET offset );
这将在结果集中移动当前位置,并返回之前的位置。
注意:
这对函数对于在结果集中的已知点之间的移动非常有用。但请小心不要混淆了由row_tell和row_seek使用的偏移量和data_seek使用的行号。否则,结果将变得不可预知。

[5] mysql_free_result
void mysql_free_result( MYSQL_RES *result );
完成了对数据集的操作后,你必须总是调用此函数来让MySQL库清理它分配的对象。

例子:
选择所有年龄大于100的记录。
select1.c

使用用户wcdj登录mysql
$ mysql -u wcdj -p newdatabase
Enter password:
Welcome to the MySQL monitor. Commands end with ; or /g.
显示表中的所有数据
mysql> SELECT * FROM children;

[cpp:collapse] view plaincopy?
  1. #include <stdlib.h>  
  2. #include <stdio.h>  
  3. #include "mysql.h"  
  4. MYSQL my_connection;  
  5. MYSQL_RES *res_ptr;  
  6. MYSQL_ROW sqlrow;  
  7. int main(int argc, char *argv[])  
  8. {  
  9.     int res;  
  10.     mysql_init(&my_connection);  
  11.     if(mysql_real_connect(&my_connection, "localhost""wcdj""123""newdatabase", 0, NULL, 0))  
  12.     {  
  13.         printf("Connection success/n");  
  14.         res = mysql_query(&my_connection, "SELECT childno, fname, age FROM children WHERE age > 100");  
  15.             if (res)  
  16.             {  
  17.                 printf("SELECT error: %s/n", mysql_error(&my_connection));  
  18.             }  
  19.             else// ok  
  20.             {  
  21.                 res_ptr = mysql_store_result(&my_connection);  
  22.                 if (res_ptr)// ok  
  23.                 {  
  24.                     printf("Retrieved %lu rows/n", (unsigned long)mysql_num_rows(res_ptr));// ok  
  25.                     while ((sqlrow = mysql_fetch_row(res_ptr)))  
  26.                     {  
  27.                         printf("Fetched data.../n");// ok  
  28.                     }  
  29.                     if (mysql_errno(&my_connection))  
  30.                     {  
  31.                         fprintf(stderr, "Retrive error: %s/n", mysql_error(&my_connection));  
  32.                     }  
  33.                     mysql_free_result(res_ptr);  
  34.                 }  
  35.             }  
  36.             mysql_close(&my_connection);  
  37.     }  
  38.     else   
  39.     {  
  40.         fprintf(stderr, "Connection failed/n");  
  41.         if (mysql_errno(&my_connection))  
  42.         {  
  43.             fprintf(stderr, "Connection error %d: %s/n", mysql_errno(&my_connection),  
  44.                 mysql_error(&my_connection));  
  45.         }  
  46.     }  
  47.     return EXIT_SUCCESS;  
  48. }  

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

 

(2) 一次提取一行数据的函数
MYSQL_RES *mysql_use_result(MYSQL *connection);
与mysql_store_result函数一样,mysql_use_result在遇到错误时也返回NULL。如果成功,它返回指向结果集对象的指针。但是,不同之处在于它未将提取的数据放到它初始化的结果集中。
注意
为了真正得到数据,你必须反复调用mysql_fetch_row直到提取了所有的数据。如果没有从mysql_use_result中得到所有数据,那么程序中后续的提取数据操作可能会返回遭到破坏的信息。

调用mysql_use_result和调用mysql_store_result的效果有何不同 呢?
【1】mysql_use_result的缺点
1、前者具备资源管理方面的实质性好处,但是它不能与mysql_data_seek、mysql_row_seek或mysql_row_tell一起使用,并且由于直到所有数据都被提取后才能实际生效,mysql_num_rows的使用也受到限制。
2、而且,还增加了时延,因为每个行请求和结果的返回都必须通过网络。
3、另外还存在一种可能性是,网络连接可能在操作中途失败,留给你不完整的数据。
【2】mysql_use_result的优点
但是,无论怎样,上述缺点都不会抹去mysql_use_result带来的好处:更好地平衡了网络负载,以及减少了可能非常大的数据集带来的存储开销。

例子:
这里使用mysql_use_result函数
select2.c

 

[cpp:collapse] view plaincopy?
  1. #include <stdlib.h>  
  2. #include <stdio.h>  
  3. #include "mysql.h"  
  4. MYSQL my_connection;  
  5. MYSQL_RES *res_ptr;  
  6. MYSQL_ROW sqlrow;  
  7. int main(int argc, char *argv[])  
  8. {  
  9.     int res;  
  10.     mysql_init(&my_connection);  
  11.     if(mysql_real_connect(&my_connection, "localhost""wcdj""123""newdatabase", 0, NULL, 0))  
  12.     {  
  13.         printf("Connection success/n");  
  14.         res = mysql_query(&my_connection, "SELECT childno, fname, age FROM children WHERE age > 100");  
  15.         if (res)  
  16.         {  
  17.             printf("SELECT error: %s/n", mysql_error(&my_connection));  
  18.         }  
  19.         else// ok  
  20.         {  
  21.             //res_ptr = mysql_store_result(&my_connection);  
  22.             res_ptr = mysql_use_result(&my_connection);// mysql_use_result  
  23.             if (res_ptr)// ok  
  24.             {  
  25.                 printf("Retrieved %lu rows/n", (unsigned long)mysql_num_rows(res_ptr));// ok, 0  
  26.                 while ((sqlrow = mysql_fetch_row(res_ptr)))  
  27.                 {  
  28.                     printf("Fetched data.../n");// ok  
  29.                 }  
  30.                 if (mysql_errno(&my_connection))  
  31.                 {  
  32.                     fprintf(stderr, "Retrive error: %s/n", mysql_error(&my_connection));  
  33.                 }  
  34.                 mysql_free_result(res_ptr);  
  35.             }  
  36.         }  
  37.         mysql_close(&my_connection);  
  38.     }  
  39.     else   
  40.     {  
  41.         fprintf(stderr, "Connection failed/n");  
  42.         if (mysql_errno(&my_connection))  
  43.         {  
  44.             fprintf(stderr, "Connection error %d: %s/n", mysql_errno(&my_connection),  
  45.                 mysql_error(&my_connection));  
  46.         }  
  47.     }  
  48.     return EXIT_SUCCESS;  
  49. }  

编译程序:
$ gcc -I/usr/include/mysql select2.c -L/usr/lib/mysql -lmysqlclient -o select2

注意
在提取最后一个结果之前,你仍然无法得到行数(测试,mysql_nuw_rows此时返回结果为0)。但是,通过早期和经常性的错误检查,可以使得程序调整为使用mysql_use_result变得更加容易。以这种方式编写代码可以减少许多程序后期修改带来的烦恼。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多