使用C语言连接数据
一、引入库
要使用C语言连接MySQL,需要使用MySQL官网提供的库。
- 方式一
如果我们使用的是
Linux
系统的话我们可以直接使用,下面的命令安装MySQL给我们提供的官方库:
sudo yum install mysql-community-devel
下载完以后我们可以在
/usr/include/mysql/
(其他系统可能会有差别)看到头文件:
ls /usr/include/mysql/
在
/usr/lib64/mysql/
看到对应的库:
ls /usr/lib64/mysql/
- 方式二
1、手动下载库
首先,进入MySQL官网,选择DOWNLOADS(下载),然后点击MySQL Community (GPL) Downloads。如下:
接下来选择Download Archives
最后选择适合自己平台的
mysql connect
库,然后点击下载就行了。如下:
2、上传至云服务器
因为这里我要在Linux服务器上使用,所以将其上传到云服务器,我准备将下载的库文件存放在一个名为
mysqllib
的目录下。
使用rz 命令将刚才下载的库文件上传到云服务器。如下:
rz
然后使用
tar
命令将压缩包解压到当前目录下。如下:
tar-xzf mysql-connector-c-6.1.11-linux-glibc2.12-x86_64.tar.gz
为了方便使用我们将名称更改一下:
mv mysql-connector-c-6.1.11-linux-glibc2.12-x86_64 mysql-connector-c
进入解压后的目录当中,可以看到有一个
include
子目录和一个
lib
子目录。如下:
其中,
include
目录下存放的一堆头文件。如下:
而
lib
目录下存放的就是动静态库。如下:
由于我们要使用的是动态库,所以当我们使用
gcc
编译时要使用
-I
命令后面跟对应的头文件路径,使用
-L
指定库的路径,使用
-l
连接具体的库。(这里为
-l mysqlclient
)
二、使用库
mysqlclient
给我们提供了许多API,其官方手册中可以看到许多细节内容,此外还有一些关于
mysqlclient
库中一些结构体对象的含义可以看这里。
1、简单示例
为了确保我们能够正常的将库引入进我们的代码中,我们可以先使用
mysql_get_client_info()
函数来进行测试。
- 此函数的功能就是返回一个记录了
mysql
客户端版本库的字符串。
代码如下:
#include<stdio.h>#include<mysql/mysql.h>intmain(){constchar* str =mysql_get_client_info();printf("%s\n", str);return0;}
为了方便后续重复编译源文件,可以在项目目录下创建一个Makefile,Makefile当中的内容如下:
说明:
Makefile
是一个文件,里面编写了一些关于进行编译和链接的命令,有了它我们就可以使用make
命令直接编译整个文件。- 这里我们没有指定头文件的搜索路径,因为我们
mysql
头文件在/usr/inclue
目录下,这是gcc
编译时的默认搜索路径,所以我们不需要指定。
编译运行成功:
从运行结果我们能够看出我们使用的客户端库版本是
5.744
,此外我们还可以使用
ldd
命令查看程序运行所需要的库:
至此库已经成功被引入,我们下面正式开始学习库接口的使用。
2、连接数据库
创建MYSQL对象
在连接数据库之前,需要先创建一个
MySQL
对象,创建MySQL对象的函数如下:
说明:
- 该函数用来分配或者初始化一个MySQL对象,用于连接MySQL服务器。
- 如果传入的参数是NULL,那么
mysql_init
将自动为你分配一个MySQL对象并返回。 - 如果传入的参数是一个地址,那么
mysql_init
将在该地址处帮你完成初始化。
MYSQL对象中包含了各种信息,其类型定义如下:
- MYSQL对象中的
methods
变量是一个结构体变量,该变量里面保存着很多函数指针,这些函数指针将会在数据库连接成功以后的各种数据操作中被调用。
连接数据库
创建完MySQL对象后就可以连接数据库了,连接数据库的函数如下:
参数说明:
mysql
: 表示在连接数据库前,调用mysql_init
函数创建的MySQ`对象。host
: 表示需要连接的MySQL服务器的IP地址,127.0.0.1
或者localhost
表示连接本地MySQL服务器。user
: 表示连接MySQL服务器时,所使用用户的用户名。passwd
: 表示连接MySQL服务器时,所使用用户的密码db
: 表示连接MySQL服务器后,需要使用的数据库。port
: 表示连接的MySQL服务器,所对应的端口号。unix_socket
: 表示连接时使用的套接字或命名管道,设置为NULL表示使用TCP/IP进行连接。clientflag
: 可以设置为多个标志位的组合,表示允许特定的功能,这里我们不使用所以设置为0。
返回值:
- 如果连接数据库成功,则返回一个MySQL对象,该对象与第一个参数的值相同。
- 如果连接数据库失败,则返回NULL。
设置连接的编码格式
当我们使用
mysql_real_connect
建立好链接之后,获取英文字符是没有问题,但是如果是获取中文则是乱码,因为MySQL默认连接的编码格式采用
latin1
,所以我们需要设置连接的编码格式。
参数:
mysql
: 表示在连接数据库前,调用mysql_init
函数创建的MySQL对象。csname
: 表示要设置的编码格式,如"utf8"。
返回值:
- 返回值为0表示设置成功,否则表示设置失败。
关闭数据库连接
与数据库交互完毕后,需要关闭数据库连接释放资源,关闭数据库连接的函数如下:
说明:
- 该函数的参数,就是连接数据库前调用
mysql_init
创建的MySQL对象。
比如使用如下代码连接我的MySQL服务器:
#include<stdio.h>#include<errno.h>#include<unistd.h>#include<mysql/mysql.h>constchar* host ="localhost";constchar* user ="qiling";constchar* password ="123456";constchar* db ="db1";u_int32_t port =3309;intmain(){// 1.初始化MYSQL对象
MYSQL* my =mysql_init(NULL);if(!my){perror("mysql_init fail: ");exit(errno);}// 2.连接MySQL服务器if(!mysql_real_connect(my, host, user, password, db, port,NULL,0)){perror("mysql_real_connect fail: ");exit(errno);}// 3. 设置连接的编码格式if(0!=mysql_set_character_set(my,"utf8")){perror("mysql_set_character_set fail: ");exit(errno);}// 休眠10s,方便我们观察实验现象sleep(10);// 4. 关闭连接,释放对象mysql_close(my);return0;}
我们编译运行此代码,同时让
root
用户使用
show processlist
命令查看登录状况。
可以看到,确实有一个叫
qiling
的用户连接了数据库,说明我们的连接成功了。
3、下发SQL请求
与数据库建立连接期间,就可以向MySQL服务器下发SQL请求,下发SQL请求的函数如下:
参数:
mysql
: 表示在连接数据库前,调用mysql_init
函数创建的MySQL对象。stmt_str
: 表示向MySQL服务器下发的SQL请求,SQL最后可以不带分号。
返回值:
- 返回值为0表示SQL执行成功,否则表示SQL执行失败。
测试表结构
这个账户表中我们设置主键为
id
并且自增,然后主要信息包含两个字段,
name
名称,
balance
余额。
通过下面的代码,我们进行测试:
- 先向这个数据库中插入两条信息:Peter,2398.4 ;张三, 3476.9。 (增)
#include<stdio.h>#include<errno.h>#include<unistd.h>#include<mysql/mysql.h>constchar* host ="localhost";constchar* user ="qiling";constchar* password ="123456";constchar* db ="db1";u_int32_t port =3309;intmain(){// 1.初始化MYSQL对象
MYSQL* my =mysql_init(NULL);if(!my){perror("mysql_init fail: ");exit(errno);}// 2.连接MySQL服务器if(!mysql_real_connect(my, host, user, password, db, port,NULL,0)){perror("mysql_real_connect fail: ");exit(errno);}// 3. 设置连接的编码格式if(0!=mysql_set_character_set(my,"utf8")){perror("mysql_set_character_set fail: ");exit(errno);}// 4.下达SQL指令// 4.1 增加信息constchar* sql ="insert into account(name, balance) values('Peter', 2398.4),('张三',3476.9)";if(0!=mysql_query(my, sql)){perror("mysql_query fail: ");exit(errno);}// 5. 关闭连接,释放对象mysql_close(my);return0;}
编译运行我们的代码,发现确实向表中新插入了两条数据,并且数据没有乱码。
- 然后将张三的名称改为Alex。(改)
....constchar* sql ="update account set name = 'Alex' where name='张三'";....
- 最后删除Peter的这条记录。 (删)
....constchar* sql ="delete from account where name = 'Peter'";...
至此为止我们现在增删改的操作都能够进行了!
4、获取查询结果
数据存储
当我们对数据库中的数据进行增删改操作时,我们只关心操作有没有成功。
而对数据库中的数据进行查询操作时,除了需要知道有没有成功,还需要获取查询结果。
获取查询结果的函数如下:
说明:
- 该函数会调用指定MySQL对象中
st_mysql_methods
中的read_rows
函数指针来获取查询的结果,并将获取到的查询结果保存到MYSQL_RES
变量中进行返回。 - 需要注意的是,
MYSQL_RES
变量的内存空间是malloc
出来的,因此在使用完后需要调用mysql_free_result
函数进行释放,否则会造成内存泄露。
MYSQL_RES
变量中保存了查询得到的各种信息,其类型定义如下:
获取查询结果的行数
获取查询结果的行数的函数如下:
说明:
- 该函数将会从指定的
MYSQL_RES
对象中,获取查询结果的行数。
获取查询结果的列数
获取查询结果的列数的函数如下:
说明:
- 该函数将会从指定的
MYSQL_RES
对象中,获取查询结果的列数。
获取查询结果的列属性
说明:
- 该函数将会从指定的MYSQL_RES对象中,获取查询结果的列属性。
mysql_fetch_fields
函数将会返回一组
MYSQL_FIELD
对象,这组对象的地址是连续的,每个
MYSQL_FIELD
对象中保存着对应列的各种列属性,其类型定义如下:
获取查询结果中的一行数据
获取查询结果中的一行数据的函数如下:
说明:
- 该函数将会从指定的
MYSQL_RES
对象中,获取查询结果中的一行数据。 - 该函数内部会记录当前我们访问到了哪一行,不需要我们手动控制,我们只需要不断调用就能拿到所有的行数据。
MYSQL_ROW
对象中保存着一行数据,这一行数据中可能包含多个字符串,对应就是这行数据中的多个列信息,因此MYSQL_ROW本质就是
char**
类型,我们将其可以当成一个
char*
的指针数组,其类型定义如下:
释放结果集
在前面我们说过
MYSQL_RES
变量的内存空间是
malloc
出来的,因此在使用完后需要调用
mysql_free_result
函数进行释放,否则会造成内存泄露。
mysql_free_result
函数的原型如下:
只需要我们传递我们结果集对应的指针就行了
查询示例
为了让数据多一些,我们先多插入一些数据:
比如查询
account
表中的数据并进行打印输出。如下:
#include<stdio.h>#include<errno.h>#include<unistd.h>#include<mysql/mysql.h>constchar* host ="localhost";constchar* user ="qiling";constchar* password ="123456";constchar* db ="db1";u_int32_t port =3309;intmain(){// 1.初始化MYSQL对象
MYSQL* my =mysql_init(NULL);if(!my){perror("mysql_init fail: ");exit(errno);}// 2.连接MySQL服务器if(!mysql_real_connect(my, host, user, password, db, port,NULL,0)){perror("mysql_real_connect fail: ");exit(errno);}// 3. 设置连接的编码格式if(0!=mysql_set_character_set(my,"utf8")){perror("mysql_set_character_set fail: ");exit(errno);}// 4.下达SQL指令constchar* sql ="select * from account";if(0!=mysql_query(my, sql)){perror("mysql_query fail: ");exit(errno);}// 5.获得存储结果
MYSQL_RES* my_res =mysql_store_result(my);// 5.1获得结果集中的行数
my_ulonglong rows =mysql_num_rows(my_res);// 5.2获得结果集中的列数u_int32_t column =mysql_num_fields(my_res);// 5.3获得结果集中的字段属性
MYSQL_FIELD* filed_array =mysql_fetch_fields(my_res);// 5.4获取结果集中的数据,并进行打印// 打印字段的属性for(int i =0; i < column; i++){printf("%s\t", filed_array[i].name);}printf("\n");printf("----------------------------\n");// 打印字段的数据for(int i =0; i < rows; i++){
MYSQL_ROW row_data =mysql_fetch_row(my_res);for(int j =0; j < column; j++){printf("%s\t", row_data[j]);}printf("\n");}// 6.释放结果集mysql_free_result(my_res);// 7. 关闭连接,释放对象mysql_close(my);return0;}
三、事务操作
对于事务的操作我们也可以使用
mysql_query()
函数进行开启一个事务,然后进行处理事务,下面我们介绍一些关于控制事务操作的一些API。
设置事务提交模式
参数:
mysql
,我们使用mysql_init()
函数创建出来的mysql对象- 如果
mode
为 1,则将自动提交模式设置为on
,如果mode
为0
,则将自动提交模式设置为off
。
返回值:
- 如果成功,返回0,如果出现错误,返回非0值。
提交事务
参数:
mysql
,我们使用mysql_init()
函数创建出来的mysql对象
返回值:
- 如果成功,返回0,如果出现错误,返回非0值。
事务回滚
参数:
mysql
,我们使用mysql_init()
函数创建出来的mysql对象
返回值:
- 如果成功,返回0,如果出现错误,返回非0值。
四、错误处理
返回错误的描述
参数:
mysql
,我们使用mysql_init()
函数创建出来的mysql对象
返回值
- 返回错误的描述对应的字符串
返回错误的编号
参数:
mysql
,我们使用mysql_init()
函数创建出来的mysql对象
返回值
- 返回错误的编号
下面的代码我们
- 先开启一个事务,然后插入一条数据
smith, 3478.9
。 - 然后修改金额为
8907.6
- 然后提交该事务。
- 之后我们再次开启一个事务,
- 然后再插入一条数据
Lisa, 4588.7
。 - 最后进行数据回滚。
根据代码我们最后插入的数据应该只有
smith,8907.6
,这是我们表的初始状态:
#include<stdio.h>#include<errno.h>#include<unistd.h>#include<mysql/mysql.h>constchar* host ="localhost";constchar* user ="qiling";constchar* password ="123456";constchar* db ="db1";u_int32_t port =3309;intmain(){// 1.初始化MYSQL对象
MYSQL* my =mysql_init(NULL);if(!my){perror("mysql_init fail: ");exit(errno);}// 2.连接MySQL服务器if(!mysql_real_connect(my, host, user, password, db, port,NULL,0)){perror("mysql_real_connect fail: ");exit(errno);}// 3. 设置连接的编码格式if(0!=mysql_set_character_set(my,"utf8")){perror("mysql_set_character_set fail: ");exit(errno);}// 4.下达SQL指令 开启事务mysql_autocommit(my,1);mysql_query(my,"begin");mysql_query(my,"insert into account(name, balance) values('smith', 3478.9)");mysql_query(my,"update account set balance=8907.6 where name='smith'");mysql_commit(my);mysql_query(my,"begin");mysql_query(my,"insert into account(name, balance) values('lisa', 4588.7)");mysql_rollback(my);// 5. 关闭连接,释放对象mysql_close(my);return0;}
最后的运行结果符合我们的预期:
版权归原作者 七凌、 所有, 如有侵权,请联系我们删除。