8.3    使用C语言訪问MySQL数据

8.3.3 运行SQL语句

运行SQL语句的主要API函数被恰当的命名为:

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

这个例程接受连接结构指针和文本字符串形式的有效SQL语句,假设成功,它返回0.

1.不返回数据的SQL语句

为简单起见,先看一些不返回不论什么数据的SQL语句:UPDATE,DELETE和INSERT.

以下的函数用于检查受查询影响的行数:

my_ulonglong mysql_affected_rows(MYSQL *connection);

这个函数的返回值类型非常不常见,它使用无符号类型是出于移植性的考虑.当使用printf时,最好使用%lu格式将其转换为无符号长整形.这个函数返回受之前运行的UPDATE,DELETE和INSERT查询影响的函数.MySQL返回的是被一个更新操作改动的行数.

通常对于mysql_系列函数,返回值0表示没有行受到影响,正数则是实际的结果,一般表示受影响的行数.

编敲代码insert1.c,尝试在表中插入一个新行.

mysql_affected_rows返回实际对数据进行的改动或者插入的行数.此外当从数据库中删除数据时,假设使用WHERE子句删除数据,那么mysql_affected_rows将返回删除的行数.但假设在DELETE语句中卖没有WHERE子句,那么表中的全部行都会被删除,可是由程序返回的受影响的行数却为0.这是由于MySQL优化了删除全部行的操作,它并非运行很多个单行删除操作.

2.发现插入的内容

auto_increment类型由MySQL自己主动分配ID,这一特性很实用,特别是当有很多用户的时候.

CREATE TABLE children(

        childno int auto_increment NULL PRIMARY KEY,

        fname varchar(30),

        age int

);

MySQL提供函数LAST_INSERT_ID()给出了auto_increment列的值.

不管何时MySQL向auto_increment列中插入数据,MySQL都会基于每一个用户对最后分配的值进行跟踪.用户程序能够通过SELECT专用函数LAST_INSERT_ID()来发现该值,这个函数的作用有点像表中的虚拟列.

编敲代码insert2.c

3.返回数据的语句

SQL最常见的使用方法当然是提取数据而不是插入或更新数据.数据是使用SELECT语句提取的.

MySQL也支持使用SQL语句SHOW,DESCRIBE和EXPLAIN来返回结果,临时不涉及它们.

在C应用程序中提取数据一般须要以下4个步骤:

运行查询

提取数据

处理数据

必要的清理工作


就像之前的INSERT和DELETE语句一样,将使用mysql_query来发送SQL语句运行查询,然后使用mysql_store_result或mysql_use_result来提取数据,详细使用哪个函数取决于想怎样提取数据.接着将使用一系列mysql_fetch_row调用来处理数据,最后使用mysql_free_result释放查询占用的内存资源.

mysql_use_result和mysql_store_result的差别主要在于,是想一次返回一行数据,还是一次返回全部的结果.当语句结果集较小时,后者比較合适.

一次提取全部数据的函数

能够使用mysql_store_result在一次调用中从SELECT中提取全部数据:

MYSQL_RES *mysql_store_result(MYSQL *connection);

显然,须要在成功调用mysql_query之后使用此函数.这个函数将立马保存从client中返回的数据.它返回一个指向结果集结构的指针,假设失败返回NULL.

my_ulonglong mysql_num_rows(MYSQL_RES *result);

这个函数接受由mysql_store_result返回的结果,并返回的结果结构,并返回结果集中的行数.假设mysql_store_result调用成功,mysql_num_rows将始终都是成功的.

假设使用的是一个特别庞大的数据集,那么最好提取小一些,更easy管理的信息块,由于这将更快地将控制权返回给应用程序,而且不会占用大量的网络资源.

使用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);

可是能够这样使用它的返回值:

MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES *result, MYSQL_ROW_OFFSET offset);

这将在结果集中移动当前位置,并返回之前的值.

这对函数对于结果集中的已知点之间的移动很实用.可是不要混淆由row_tell和row_seek使用的偏移量和data_seek使用的行号.

4.完毕了对数据的全部操作之后,必须明白地调用mysql_free_result来让MySQL库完毕善后处理.

提取数据

编敲代码select1.c提取全部年龄大于5的记录

#include <stdlib.h>
#include <stdio.h>
#include "mysql.h" int main(int argc, char *argv[]){
int res;
MYSQL my_connection;
MYSQL_RES *res_ptr;
MYSQL_ROW sqlrow; mysql_init(&my_connection);
//初始化连接句柄,返回一个指向新分配的连接句柄的指针,仅仅是分配和初始化了一个结构
if (mysql_real_connect(&my_connection, "localhost", "rick","secret", "foo", 0, NULL, 0)){
//mysql_real_connect向一个连接提供參数,指针connection指向已经被mysql_init初始化过的结构
printf("Connection success\n");
res = mysql_query(&my_connection, "SELECT childno, fname, age FROM children WHERE age > 5");
//mysql_query參数为结构指针和文本字符串形式的SQL语句,假设成功则运行字符串表示的SQL语句,返回0
if (res){
printf("SELECT error: %s\n", mysql_error(&my_connection));
}else{
res_ptr = mysql_store_result(&my_connection);
//mysql_store_result在一次调用中从SELECT中提取全部数据,返回指向结果集结构的指针
if (res_ptr){
printf("Retrieved %lu rows\n", (unsigned long)mysql_num_rows(res_ptr));
//mysql_num_rows得到返回记录的数目,接受由mysql_store_result返回的结果结构指针
while((sqlrow = mysql_fetch_row(res_ptr))){
//mysql_fetch_row从mysql_store_result的结果结构中提取一行
printf("Fetched data...\n");
}
if (mysql_errno(&my_connection)){
//mysql_errno返回错误码,非零
fprintf(stderr, "Retrieve error: %s\n", mysql_error(&my_connection));
//mysql_error返回错误的文本信息
}
mysql_free_result(res_ptr);
//mysql_free_result释放查询占用的内存资源
}
}
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;
}

linux程序设计——运行SQL语句(第八章)的更多相关文章

  1. SQL Server中存储过程比直接运行SQL语句慢的原因

    原文:SQL Server中存储过程比直接运行SQL语句慢的原因 在很多的资料中都描述说SQLSERVER的存储过程较普通的SQL语句有以下优点: 1.       存储过程只在创造时进行编译即可,以 ...

  2. 开始使用 Docker (Linux 上运行 SQL Server) 上的 SQL Server 容器 - SQL Server | Microsoft Docs

    原文:开始使用 Docker (Linux 上运行 SQL Server) 上的 SQL Server 容器 - SQL Server | Microsoft Docs 快速入门:使用 Docker ...

  3. 如何在 Linux 上用 SQL 语句来查询 Apache 日志

    Linux 有一个显著的特点,在正常情况下,你可以通过日志分析系统日志来了解你的系统中发生了什么,或正在发生什么.的确,系统日志是系统管理员在解决系统和应用问题时最需要的第一手资源.我们将在这篇文章中 ...

  4. Mysql 将结果保存到文件 从文件里运行sql语句 记录操作过程(tee 命令的使用)

    1.  有时候我们可能须要记录我们对mysql的操作过程,这时我们能够使用mysql的tee命令 1)第一种情况是在链接数据库的时候使用tee >mysql  -u root  -p  --te ...

  5. SQL Server中存储过程 比 直接运行SQL语句慢的原因

    问题是存储过程的Parameter sniffing     在很多的资料中都描述说SQLSERVER的存储过程较普通的SQL语句有以下优点: 1. 存储过程只在创造时进行编译即可,以后每次执行存储过 ...

  6. 打开iBatis显示运行sql语句

    将ibatis log4j运行级别调到DEBUG可以在控制台打印出ibatis运行的sql语句,方便调试: log4j.logger.com.ibatis=DEBUG log4j.logger.com ...

  7. 使用Navicat客户端运行SQL语句出现中文乱码

    出现乱码无非就是编码方式不统一造成的,通过查阅资料解决了问题. (简 体中文系统环境支持国标 GB2312.GB18030 和 Unicode (UTF-8) 编码.它们在系统中设置的locale(亦 ...

  8. 如何在linux中运行sql文件

    1.在linux中进入sql命令行 mysql -u root -p   输入密码 2.假设home下面有a.sql文件 先得use databasename,要不会报错 “No Database S ...

  9. linux中运行.sql文件

    1.linux目录结构 2.假设home下面有a.sql文件 先得use databasename,要不会报错 “No Database Selected” 然后source /home/a.sql ...

随机推荐

  1. C#常见问题总结(三)

    11.sql比access好在哪里,为什么都用sql 解决方法: 数据量大,可以在服务器端,access一般在单机的时候用 12.c#基础视频教程有吗 解决方法: 零基础学C#这本书带全套C#基础视频 ...

  2. 【转】jvm类加载

    类加载机制 JVM把class文件加载的内存,并对数据进行校验.转换解析和初始化,最终形成JVM可以直接使用的Java类型的过程就是加载机制. 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的生命 ...

  3. Struts工作机制

    Struts工作机制? 为什么要使用Struts?工作机制:Struts的工作流程:在web应用启动时就会加载初始化ActionServlet,ActionServlet从struts-config. ...

  4. MySQL:INSERT ... UPDATE

    在 INSERT 语句末尾指定ON DUPLICATE KEY UPDATE时,如果插入的数据会导致表中的 UNIQUE 索引或 PRIMARY KEY 出现重复值,则会对导致重复的数据执行 UPDA ...

  5. java8 foreach不能使用break、countinue

    在学习1.8新特性的过程中,发现foreach中不可以使用break和countinue,然后我使用了return,结果如下图,对循环并没有影响. 百度一下,发现了一个不一样的回答 然后我就看了下源码 ...

  6. 06二叉树、Map、Collections、适配器

    06二叉树.Map.Collections.适配器-2018/07/16 1.set集合,无索引,不可以重复,无序(存取不一致) 2.TreeSet用来对象元素进行排序,可以保证元素唯一 储存自定义对 ...

  7. C++字符串处理函数总结

    1.基础函数输入输出:cin,cout,getchar,gets,putchar,puts,printf,scanf格式化:sprintf,sprintf_s,wsprintf,wsprintf_s, ...

  8. docker 部署spring.boot项目【一】(引用外部配置文件)

    上一篇随笔,nginx是启动运行在容器内,spring.boot的web项目是运行在宿主内,这一篇的目的,是把web项目也制作成镜像,然后在容器里启动. 文件目录结构如下: 主要文件结构说明:(1)b ...

  9. highcharts图表的常见操作

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  10. 【Codeforces 246D】Colorful Graph

    [链接] 我是链接,点我呀:) [题意] 让你找到所有和x颜色的点中,和该颜色的点颜色不同的相邻的点的个数(重复颜色算一次) 求出哪种颜色的所要求的点的数量最多. [题解] 对于每一条边只会被查到两次 ...