热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

在MySQL数据库中使用C执行SQL语句的方法_MySQL

在MySQL数据库中使用C执行SQL语句的方法
bitsCN.com 他们将讨论返回数据的语句,例如INSERT以及不返回数据的语句,例如UPDATE和DELETE。然后,他们将编写从数据库检索数据的简单程序

执行SQL语句

现在,我们已经有了一个连接,并且知道如何处理错误,是时候讨论使用我们的数据库来作一些实际工作了。执行所有类型的SQL的主关键字是mysql_query:

int mysql_query(MYSQL *connection, const char *query)

正如您所见,它非常简单。它取一个指向连接结构的指针和包含要执行的SQL的文本字符串;与命令行工具不同,将不使用结束分号。成功之后,返回0。在需要包含二进制数据的特殊情况下,可以使用相关的函数,mysql_real_query。虽然出于本章的目的,我们仅需要讨论mysql_query。
不返回数据的SQL语句

我们将先讨论UPDATE、DELETE和INSERT语句。因为它们不返回数据,所以更易于使用。
这里我们将介绍的另一个重要函数是检查受影响的行数的函数:

my_ulonglong mysql_affected_rows(MYSQL *connection);

可能关于这一函数的最显而易见的事就是其非同寻常的返回结果。由于可移植性原因,这是一个特殊的无符号类型。为了在printf中使用,建议将其强制转换成使用%lu格式规范的无符号长整数。这个函数返回受以前的UPDATE、INSERT或DELETE查询影响的行数,这些查询是使用mysql_query执行的。
通常对于mysql_函数,返回码0表示没有行受影响;正数表示实际结果,通常是受影响的行数。
如前所述,当使用mysql_affected_rows时可能出现未期望的结果。让我们先讨论受INSERT语句影响的行数,它将按预期进行操作。将下列代码添加到程序 connect2.c 中,并且称其为insert1.c: #include
#include
#include "mysql.h"
int main(int argc, char *argv[]) {
MYSQL my_connection;
int res;
mysql_init(&my_connection);
if (mysql_real_connect(&my_connection, "localhost",
"rick", "bar", "rick", 0, NULL, 0)) {
printf("Connection success/n");
res = mysql_query(&my_connection,
"INSERT INTO children(fname,age),
VALUES('Ann',3)");
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));
}
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。
现在,我们更改代码,所以 'insert' 部分被替换成: mysql_errno(&my_connection), mysql_error(&my_connection));
}
}
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));
}


现在假设子表中有的数据,如下:
childnofnameage
1

2

3

4

5

6

7

8

9

10

11

Jenny

Andrew

Gavin

Duncan

Emma

Alex

Adrian

Ann

Ann

Ann

Ann

14

10

4

2

0

11

5

3

4

3

4

如果我们执行update1,希望报告的受影响行数为4,但是实际上程序报告2,因为它仅必须更改2行,虽然WHERE子句标识了4行。如果想让mysql_affected_rows报告的结果为4这可能是熟悉其它数据库的人所期望的),则需要记住将CLIENT_FOUND_ROWS标志传递到mysql_real_connect,在 update2.c中的程序如下:


if (mysql_real_connect(&my_connection, "localhost",
"rick", "bar", "rick", 0, NULL, CLIENT_FOUND_ROWS)) {


如果我们在数据库中复位数据,然后运行带有这种修改的程序,则它报告的行数为4。
函数mysql_affected_rows还有最后一个奇怪之处,它发生在从数据库中删除数据时。如果使用WHERE子句,则mysql_affected_rows将按预期返回删除行数。但是,如果没有WHERE子句,则删除所有行,报告受影响的行数却为0。这是因为由于效率原因优化删除整个表。这种行为不受CLIENT_FOUND_ROWS选项标志的影响。

返回数据的语句

现在是时候讨论SQL的最普遍用法了,从数据库检索数据的SELECT语句。

MySQL 还支持返回结果的SHOW、DESCRIBE和EXPLAIN SQL语句,但是这里不考虑它们。按惯例,手册中包含这些语句的说明。
您将会从PostgreSQL章记起,可以从PQexec中的SQL SELECT 语句检索数据,这里马上获取所有数据,或者使用游标从数据库中逐行检索数据,以便搞定大数据。
由于完全相同的原因,MySQL的检索方法几乎完全相同,虽然它实际上不用游标的形式描述逐行检索。但是,它提供了缩小这两种方法间差异的API,如果需要,它通常使两种方法的互换更加容易。
通常,从MySQL数据库中检索数据有4个阶段:

发出查询
检索数据
处理数据
执行所需的任何整理

象以前一样,我们使用mysql_query发出查询。数据检索是使用mysql_store_result或mysql_use_result完成的,这取决于想如何检索数据,随后使用mysql_fetch_row调用序列来处理数据。最后,必须调用mysql_free_result以允许MySQL执行任何所需的整理。
全部立即数据检索的函数
可以从SELECT语句(或其他返回数据的语句)中检索完所有数据,在单一调用中,使用mysql_store_result: MYSQL_RES *mysql_store_result(MYSQL *connection); 必须在mysql_query检索数据后才能调用这个函数,以在结果集中存储该数据。这个函数从服务器中检索所有数据并立即将它存储在客户机中。它返回一个指向以前我们从未遇到过的结构(结果集结构)的指针。如果语句失败,则返回NULL。
使用等价的PostgreSQL时,应该知道返回NULL意味着已经发生了错误,并且这与未检索到数据的情况不同。即使,返回值不是NULL,也不意味着当前有数据要处理。
如果未返回NULL,则可以调用mysql_num_rows并且检索实际返回的行数,它当然可能是0。 my_ulonglong mysql_num_rows(MYSQL_RES *result); 它从mysql_store_result取得返回的结果结构,并且在该结果集中返回行数,行数可能为0。如果mysql_store_result成功,则mysql_num_rows也总是成功的。
这种mysql_store_result和mysql_num_rows的组合是检索数据的一种简便并且直接的方法。一旦mysql_store_result成功返回,则所有查询数据都已经存储在客户机上并且我们知道可以从结果结构中检索它,而不用担心会发生数据库或网络错误,因为对于程序所有数据都是本地的。还可以立即发现返回的行数,它可以使编码更简便。如前所述,它将所有结果立即地发送回客户机。对于大结果集,它可能耗费大量的服务器、网络和客户机资源。由于这些原因,使用更大的数据集时,最好仅检索需要的数据。不久,我们将讨论如何使用mysql_use_result函数来完成该操作。
一旦检索了数据,则可以使用mysql_fetch_row来检索它,并且使用mysql_data_seek、mysql_row_seek、mysql_row_tell操作结果集。在开始检索数据阶段之前,让我们先讨论一下这些函数。 MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);


这个函数采用从存储结果中获取的结果结构,并且从中检索单一行,在行结构中返回分配给您的数据。当没有更多数据或者发生错误时,返回NULL。稍后,我们将回来处理这一行中的数据。 void mysql_data_seek(MYSQL_RES *result, my_ulonglong offset);


这个函数允许您进入结果集,设置将由下一个获取操作返回的行。offset是行号,它必须在从0到结果集中的行数减 1 的范围内。传递0将导致在下一次调用mysql_fetch_row时返回第一行。 MYSQL_ROW_OFFEST mysql_row_tell(MYSQL_RES *result);


这个函数返回一个偏移值,它表示结果集中的当前位置。它不是行号,不能将它用于mysql_data_seek。但是,可将它用于: MYSQL_ROW_OFFSET mysql_row_seek(MYSQL_RES *result, MYSQL_ROW_OFFSET offset);


它移动结果集中的当前位置,并返回以前的位置。
有时,这一对函数对于在结果集中的已知点之间跳转很有用。请注意,不要将row tell和row seek使用的偏移值与data_seek使用的行号混淆。这些是不可交换的,结果将是您所希望看到的。 void mysql_free_result(MYSQL_RES *result);


完成结果集时, 必须总是调用这个函数,以允许MySQL库整理分配给它的对象。
检索数据
现在开始编写从数据库中检索数据的第一个程序。我们将选择所有年龄大于5的行的内容。不幸的是我们还不知道如何处理这个数据,所以我们能做的只有循环检索它。这便是 select1.c: #include
#include

#include "mysql.h"

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",
"bar", "rick", 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 %luows/n",(unsignedlong)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;
}


检索结果集并循环通过已检索的数据的重要部分都已突出显示。

一次检索一行数据

要按需要逐行检索数据,而不是立即获取全部数据并将它存储在客户机中,可以将mysql_store_result调用替换成 mysql_use_result: MYSQL_RES *mysql_use_result(MYSQL *connection);


这个函数还取得一个连接对象并返回结果结合指针,或者出错时返回NULL。与mysql_store_result相似,它返回指向结果集对象的指针;关键的不同点在于返回时,实际上没有将任何数据检索到结果集,只是初始化结果集以准备好检索数据。

参考资料

您可以参阅本文在developerWorks全球站点上的英文原文.

本文章取自Wrox Press Ltd出版的Professional Linux一书的第5章。

关于作者

Rick Stones是一位系统设计师,他在一家大型泛欧制药分销和分配公司的IT部门工作。从1985年开始,他一直在使用各种形式的 UNIX,并且发现带有早期 .99 CD-ROM发行版的Linux。他用各种语言编写UNIX、Linux和其它平台的软件,同时还安装并管理几台Linux服务器。在非常有限的业余时间,他努力提高他的钢琴演奏技巧。

从大学时代开始接触C和UNIX V6时起,Neil Matthew对于UNIX和Linux已经超过20年的经验。从那时起他就在IT业工作,主要从事通信软件的开发,一直保持对于深奥的编程语言和开发技术的热情。现在,他作为系统设计师,对技术战略和QA提出建议。他热心于在公司企业内建立Linux商业案例。业余时间,写作或骑马为乐,Neil努力劝说他的妻子和两个孩子与他一起在乡间散步。Neil参与编写了Wrox Press发行的好几本书,最著名的是共同著作了Beginning Linux Programming和Professional Linux Programming。bitsCN.com
推荐阅读
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 如何在服务器主机上实现文件共享的方法和工具
    本文介绍了在服务器主机上实现文件共享的方法和工具,包括Linux主机和Windows主机的文件传输方式,Web运维和FTP/SFTP客户端运维两种方式,以及使用WinSCP工具将文件上传至Linux云服务器的操作方法。此外,还介绍了在迁移过程中需要安装迁移Agent并输入目的端服务器所在华为云的AK/SK,以及主机迁移服务会收集的源端服务器信息。 ... [详细]
  • 本文介绍了通过mysql命令查看mysql的安装路径的方法,提供了相应的sql语句,并希望对读者有参考价值。 ... [详细]
author-avatar
GYuan83_844
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有