文章目录
- 前言
- 一、Connector/C使用
- 1、下载MySQL连接所需库
- 第一种方法
- 第二种方法
- 2、MySQL库链接
- 3、MySQL接口介绍
- 连接
- 执行sql语句
- 执行查询语句
前言
一、Connector/C使用
MySQL数据库的基础知识我们前面已经学习了,下面我们就开始学习怎么将MySQL数据库和我们学习的C/C++等语言连接。要使用C语言连接mysql,需要使用mysql官网提供的库。
1、下载MySQL连接所需库
第一种方法
将文件下载解压好就是这样的,我们上传到远端的Linux服务器中。
include目录里面是连接数据库的头文件,lib目录里面是对应的动静态库。
上面的这种方法我们现在一般不使用了。
第二种方法
我们在安装MySQL数据库的时候其实已经将对应的开发包也一并下载了。所以我们就不需要再像第一种方法一样去官网下载对应的连接库了。其中 include 包含所有的方法声明, lib 包含所有的方法实现(打包成库)
注意:如果我们在/usr/include目录下没有找到mysql目录,那么是因为我们安装MySQL时并没有给我们将开发包下载了,此时我们可以执行下面的语句来手动将开发包下载。需要下载和当前数据库版本匹配的开发包。
sudo yum install -y mysql-community-devel-5.7.44-1.el7.x86_64
然后我们就可以在下面的两个目录中查看到开发包中的头文件和对应的动静态库了。
2、MySQL库链接
下面我们来通过调用mysql.h中提供的mysql_get_client_info()函数来验证我们是否成功引入MySQL连接库。
因为程序执行时会去/usr/include目录下查找头文件,所以我们在引入mysql.h头文件时,只需要指定mysql.h头文件在mysql目录下即可。
然后我们直接使用g++编译器进行编译时,发现出现了错误,这是因为我们只引入了mysql.h头文件,并没有在编译时连接到mysqlclient库,所以我们在编译时还需要手动链接到mysqlclient库。但是我们看到手动链接mysqlclient库后也出现了错误,这是因为我们没有告诉g++编译器mysqlclient库在哪个目录下,所以g++编译器会去默认的/usr/bin目录下找,如果找不到就报出错误,所以我们编译时还需要告诉g++除了去/usr/bin目录下找之外,还要去/lib64/mysql目录下找mysqlclient,这样才可以将test.cc文件编译成功。我们看到执行生成的可执行程序后,我们使用ldd命令查看可执行程序链接的库,可以看到mysqlclient被成功链接并使用。
如果我们在编写代码时,引入头文件时不想要使用/mysql/mysql.h,而想要直接使用mysql.h引入头文件,那么我们在使用g++编译时,就需要告诉g++编译器去mysql.h头文件所在的目录去查找头文件。
3、MySQL接口介绍
连接
对于MySQL链接库中接口的使用,我们可以查阅官方文档。
在MySQL的文档中,我们看到MySQL还构建了一些结构体,为了更好的使用接口函数。
我们想要使用MySQL库,就必须先进行初始化,即需要先调用mysql_init函数来进行初始化。我们看到mysql_init()函数返回一个MYSQL类型指针,并且如果没有初始化成功,那么这个函数会返回NULL。MYSQL是 C api中一个非常重要的变量(mysql_init的返回值),里面内存非常丰富,有port,dbname,charset等连接基本参数。它也包含了一个叫 st_mysql_methods的结构体变量,该变量里面保存着很多函数指针,这些函数指针将会在数据库连接成功以后的各种数据操作中被调用。
然后我们再使用mysql_real_connect函数来链接数据库。
我们需要注意当初始化了MySQL对象之后,在代码的最后也要释放MySQL对象,因为MySQL库底层使用了资源,如果我们不进行释放,那么就造成资源泄漏。host为127.0.0.1和为localhost都表示本地登录。
然后我们编写一个makefile文件来编译,当我们运行程序时,我们看到MySQL连接失败。
这时我们可以先看一下mysqld服务器进程是否在运行中,我们看到mysqld进程在运行中。然后我们使用root用户登录mysql发现并没有conn数据库,所以才会连接失败。并且我们看到并没有connector用户。
下面我们创建conn数据库,并且创建connector用户。需要注意的是我们还需要给connector用户关于conn数据库的权限,因为这样connector用户才可以访问到conn数据库。
然后我们看到我们写的程序就连接mysqld服务器成功了,此时这个程序就也是mysql的一个客户端。
如果我们此时将mysqld服务器关闭了,那么再运行这个程序就会连接数据库失败,因为mysqld服务器已经关闭了。
下面我们在代码中连接数据库后,让程序10s后退出,我们来观察数据库的连接情况。可以看到当程序启动后,那么mysql就多了一个客户端连接。
执行sql语句
我们可以通过调用mysql_query函数来在代码中下发mysql命令。该函数的第一个参数为mysql_init函数的返回值,第二个参数为要执行的sql语句,如“select * from table”。
我们先在conn数据库中创建一个user表。
然后我们来简单实现一个类似于mysql命令行客户端的程序。
然后我们运行程序,可以看到通过mytest程序向user表中插入了数据。这样我们就实现了一个最简单的MySQL客户端程序。
下面我们修改user表中的数据。
然后我们再试着向表中插入数据和删除数据。
我们前面都是向user表中插入英文数据,如果我们插入中文数据时,我们看到出现了乱码。
这是因为客户端和MySQL建立的链接默认使用的字符集是latin1,即在MySQL中将latin1字符集使用utf8字符集进行解码,所以出现了乱码。我们可以通过mysql_set_character_set()函数来设置链接的默认字符集是utf8。
mysql_set_character_set(my, "utf8");
然后我们看到中文数字也不会出现乱码了。
执行查询语句
上面我们只执行了增、删、改的sql语句,下面我们来执行查询的sql语句。
我们看到执行了select语句后,并没有什么反应,select查询到的数据也没有被显示。这是因为我们没有打印select语句查询到的数据。
当sql执行完以后,如果是查询语句,我们还要读取数据,我们可以通过mysql_store_result这个函数来读取结果。该函数会调用MYSQL变量中的st_mysql_methods中的 read_rows 函数指针来获取查询的结果。同时该函数会返回MYSQL_RES 这样一个变量,该变量主要用于保存查询的结果。同时该函数malloc了一片内存空间来存储查询过来的数据,所以我们一定要记的 free(result),不然是肯定会造成内存泄漏的。 执行完mysql_store_result以后,其实数据都已经在MYSQL_RES 变量中了,下面的api基本就是读取MYSQL_RES 中的数据。
- 获取结果行数mysql_num_rows
my_ulonglong mysql_num_rows(MYSQL_RES *res);
- 获取结果列数mysql_num_fields
unsigned int mysql_num_fields(MYSQL_RES *res);
- 获取列名mysql_fetch_fields
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res);
我们看到MYSQL_RES结构体存储select查询的结果就是采用下面的方式存储的。
然后我们打印select语句显示的结果的行数和列数。
如果我们要显示数据,那么可以使用mysql_fetch_row函数。该函数会返回一个MYSQL_ROW变量,MYSQL_ROW其实就是char **,可以当成一个二维数组来用。
我们看到上面的数据中没有列相关信息,我们可以通过mysql_fetch_fields函数来获取列相关信息。
fields_array[i]中不止有name属性,还有很多其它的属性,例如下面我们获取user表中id列所在数据库和所在表。
我们需要特别注意,当使用MYSQL_RES结构体对象后,需要调用mysql_free_result函数来释放该结构体对象申请的内存资源。因为mysql_store_result函数malloc了一片内存空间来存储查询过来的数据,所以我们一定要记的调用msql_free_result函数,不然是肯定会造成内存泄漏的。