MySQL - 第14节 - MySQL使用C语言连接

目录

1.引入库

1.1.下载库文件

1.2.在项目中使用库

2.使用库

2.1.连接数据库

2.2.下发SQL请求

2.3.获取查询结果

3.自己实现一个MySQL命令行连接客户端

4.MySQL图形化界面连接


1.引入库

要使用C语言连接MySQL,需要使用MySQL官网提供的库。

1.1.下载库文件

下载库文件:

首先,进入MySQL官网,选择DEVELOPER ZONE(开发人员专区),然后点击MySQL Downloads。如下:

MySQL官网:MySQL

MySQL - 第14节 - MySQL使用C语言连接_第1张图片

接下来选择Download Archives。如下: 

MySQL - 第14节 - MySQL使用C语言连接_第2张图片

因为我们是要使用C语言连接MySQL,所以这里选择MySQL Connector/C。如下: 

MySQL - 第14节 - MySQL使用C语言连接_第3张图片

最后选择适合自己平台的mysql connect库,然后点击下载就行了。如下: 

MySQL - 第14节 - MySQL使用C语言连接_第4张图片

上传到云服务器:

因为我下载的是Linux下使用的库文件,因此下载完毕后需要将其上传到云服务器,我准备将下载的库文件存放在一个名为thirdPath的目录下。如下:

MySQL - 第14节 - MySQL使用C语言连接_第5张图片

使用 rz -E 命令将刚才下载的库文件上传到云服务器(如果普通用户上传失败可以尝试切换root用户上传)。如下:

MySQL - 第14节 - MySQL使用C语言连接_第6张图片

然后使用 tar 命令将压缩包解压到当前目录下。如下:

为了方便后面演示,这里使用 mv 命令将解压后的目录名称改短一点。如下:

MySQL - 第14节 - MySQL使用C语言连接_第7张图片

进入解压后的目录当中,可以看到有一个include子目录和一个lib子目录。如下:

MySQL - 第14节 - MySQL使用C语言连接_第8张图片

其中,include目录下存放的一堆头文件。如下:

MySQL - 第14节 - MySQL使用C语言连接_第9张图片

而lib目录下存放的就是动静态库。如下:

注:其实我们在 “MySQL在Centos 7环境安装”博客中配置yum源并安装MySQL时,就已经安装过这些头文件和库文件了,因此这里其实也可以不再下载和上传这些头文件和库文件。

1.2.在项目中使用库

在项目中使用库:

创建项目目录MysqlConnect并进入,为了方便在项目中使用刚才的库文件,可以在项目目录下创建两个软连接,分别连接到刚才的include目录和lib目录。如下:

这时直接在项目目录下,就能看到刚才include和lib目录下的内容。如下:

MySQL - 第14节 - MySQL使用C语言连接_第10张图片

下面先通过调用mysql_get_client_info来判断库是否引入成功,该函数的作用就是获取客户端的版本信息。

创建mysql_connect.cc文件,写入下面代码。

#include 
#include 
using namespace std;

int main()
{
    //获取客户端的版本信息
    cout<<"mysql client version: "<

为了方便后续重复编译源文件,可以在项目目录下创建一个Makefile,Makefile当中的内容如下:

MySQL - 第14节 - MySQL使用C语言连接_第11张图片

说明一下:

• -I:用于指明头文件的搜索路径。

• -L:用于指明库文件的搜索路径。

• -l:用于指明需要连接库文件路径下的哪一个库。

Makefile编写完毕后,直接通过make命令即可编译代码生成可执行程序。如下:

MySQL - 第14节 - MySQL使用C语言连接_第12张图片

但此时生成的可执行程序还不能直接运行,通过ldd命令可以看到,该可执行程序所依赖的mysqlclient库找不到。如下: 

MySQL - 第14节 - MySQL使用C语言连接_第13张图片

原因如下:

• gcc/g++编译器默认都是动态链接的,编译代码时默认使用的是动态库,所以生成的可执行程序在运行时需要找到对应的动态库进行链接,而我们使用的mysqlclient库并不在系统的搜索路径下。
• 需要注意的是,Makefile中的-I,-L和-l这三个选项,只是在编译期间告诉编译器头文件和库文件在哪里,而可执行程序生成后就与编译器无关了。
解决该问题通常有三种做法:

1.将库文件拷贝到系统默认的库文件搜索路径下/lib64。
2.将库文件所在的目录路径添加到LD_LIBRARY_PATH环境变量中,该环境变量可以用于指定查找动态库时的其他路径。
3.将库文件所在的目录路径保存到以.conf为后缀的配置文件中,然后将该文件拷贝到/etc/ld.so.conf.d/目录下,并使用ldconfig命令对配置文件进行更新,该目录下所有配置文件中的路径也将作为查找动态库时的搜索路径。
这里我们采用第三种方式进行解决。使用root用户操作,如下:

MySQL - 第14节 - MySQL使用C语言连接_第14张图片

此时该可执行程序所依赖的mysqlclient库就能够被找到了。如下:

MySQL - 第14节 - MySQL使用C语言连接_第15张图片

运行可执行程序后,可以看到客户端的版本为6.1.11,也就是刚才下载的库文件的版本。如下:


2.使用库

至此库已经成功被引入,剩下就是库接口的使用问题了。

2.1.连接数据库

创建MySQL对象:

在连接数据库之前,需要先创建一个MySQL对象,创建MySQL对象的函数如下:

MYSQL* mysql_init(MYSQL *mysql);

说明一下:

• 该函数用来分配或者初始化一个MySQL对象,用于连接MySQL服务器。
• 如果传入的参数是NULL,那么mysql_init将自动为你分配一个MySQL对象并返回。
• 如果传入的参数是一个地址,那么mysql_init将在该地址处帮你完成初始化。
MYSQL对象中包含了各种信息,其类型定义如下:

typedef struct st_mysql {
	NET net;			/* Communication parameters */
    unsigned char	*connector_fd;		/* ConnectorFd for SSL */
    char *host,*user,*passwd,*unix_socket,*server_version,*host_info;
    char *info, *db;
    struct charset_info_st *charset;
    MYSQL_FIELD	*fields;
    MEM_ROOT field_alloc;
    my_ulonglong affected_rows;
    my_ulonglong insert_id;		/* id if insert on table with NEXTNR */
    my_ulonglong extra_info;		/* Not used */
    unsigned long thread_id;		/* Id for connection in server */
    unsigned long packet_length;
    unsigned int port;
    unsigned long client_flag,server_capabilities;
    unsigned int protocol_version;
    unsigned int field_count;
    unsigned int server_status;
    unsigned int server_language;
    unsigned int warning_count;
    struct st_mysql_options options;
    enum mysql_status status;
    my_bool	free_me;		/* If free in mysql_close */
    my_bool	reconnect;		/* set to 1 if automatic reconnect */

    /* session-wide random string */
    char scramble[SCRAMBLE_LENGTH+1];
    my_bool unused1;
    void *unused2, *unused3, *unused4, *unused5;

    LIST *stmts;                     /* list of all statements */
    const struct st_mysql_methods *methods;
    void *thd;
    /*
      Points to boolean flag in MYSQL_RES  or MYSQL_STMT. We set this flag
      from mysql_stmt_close if close had to cancel result set of this object.
    */
    my_bool *unbuffered_fetch_owner;
    /* needed for embedded server - no net buffer to store the 'info' */
    char *info_buffer;
    void *extension;
} MYSQL;

说明一下:

• MYSQL对象中的methods变量是一个结构体变量,该变量里面保存着很多函数指针,这些函数指针将会在数据库连接成功以后的各种数据操作中被调用。

连接数据库:

创建完MySQL对象后就可以连接数据库了,连接数据库的函数如下:

MYSQL* mysql_real_connect(MYSQL *mysql, const char *host,
					const char *user,
					const char *passwd,
					const char *db,
					unsigned int port,
					const char *unix_socket,
					unsigned long clientflag);

参数说明:

• mysql: 表示在连接数据库前,调用mysql_init函数创建的MySQL对象。
• host: 表示需要连接的MySQL服务器的IP地址,"127.0.0.1"表示连接本地MySQL服务器。
• user: 表示连接MySQL服务器时,所使用用户的用户名。
• passwd: 表示连接MySQL服务器时,所使用用户的密码
• db: 表示连接MySQL服务器后,需要使用的数据库。
• port: 表示连接的MySQL服务器,所对应的端口号。
• unix_socket: 表示连接时应该使用的套接字或命名管道,通常设置为NULL。
• clientflag: 可以设置为多个标志位的组合,表示允许特定的功能,通常设置为0。
返回值说明:

• 如果连接数据库成功,则返回一个MySQL对象,该对象与第一个参数的值相同。
• 如果连接数据库失败,则返回NULL。

关闭数据库连接:

与数据库交互完毕后,需要关闭数据库连接,关闭数据库连接的函数如下:

void mysql_close(MYSQL *sock);

说明一下:

• 该函数的参数,就是连接数据库前调用mysql_init创建的MySQL对象。

• 如果传入的MySQL对象是mysql_init自动创建的,那么调用mysql_close时就会释放这个对象。

连接示例:

比如使用如下代码连接我的MySQL服务器,将该代码覆盖到前面的mysql_connect.cc文件中。

#include 
#include 
#include 
using namespace std;

const string host = "123.60.25.237";
const string user = "root";
const string passwd = "";
const string db = "connect_demon";
const int port = 3306;

int main()
{
    //1、创建MySQL对象
    MYSQL* ms = mysql_init(nullptr);
    //2、连接数据库
    if(mysql_real_connect(ms, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr<<"数据库连接失败!"<

使用make命令生成可执行程序,运行后即可看到连接数据库成功、关闭数据库成功。如下:

2.2.下发SQL请求

下发SQL请求:

与数据库建立连接期间,就可以向MySQL服务器下发SQL请求,下发SQL请求的函数如下:

int	mysql_query(MYSQL *mysql, const char *q);

参数说明:

• mysql:表示在连接数据库前,调用mysql_init函数创建的MySQL对象。

• q:表示向MySQL服务器下发的SQL请求,SQL最后可以不带分号。

返回值说明:

• 返回值为0表示SQL执行成功,否则表示SQL执行失败。

设置编码格式:

在连接数据库之后,需要统一客户端和服务器的编码格式,避免在数据交互过程中出现乱码,设置编码格式的函数如下:

int mysql_set_character_set(MYSQL *mysql, const char *csname);

参数说明:

• mysql: 表示在连接数据库前,调用mysql_init函数创建的MySQL对象。

• csname: 表示要设置的编码格式,如"utf8"

返回值说明:

• 返回值为0表示设置成功,否则表示设置失败。

测试表介绍:

下面在与MySQL数据库交互时,访问的都是connect_demon数据库,该数据库下有一个user表,表中有三条记录。如下:

MySQL - 第14节 - MySQL使用C语言连接_第16张图片

向数据库中插入数据:

在调用mysql_query函数时,向MySQL服务器下发一条insert SQL,如下。将该代码覆盖到前面的mysql_connect.cc文件中。

#include 
#include 
#include 
using namespace std;

const string host = "123.60.25.237";
const string user = "root";
const string passwd = "";
const string db = "connect_demon";
const int port = 3306;

int main()
{
    //1、创建MySQL对象
    MYSQL* ms = mysql_init(nullptr);
    //2、连接数据库
    if(mysql_real_connect(ms, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr<<"数据库连接失败!"<

使用make命令生成可执行程序,运行后在MySQL中即可看到对应数据被成功插入。如下:

MySQL - 第14节 - MySQL使用C语言连接_第17张图片

删除数据库中的数据:

在调用mysql_query函数时,向MySQL服务器下发一条delete SQL,如下。将该代码覆盖到前面的mysql_connect.cc文件中。

#include 
#include 
#include 
using namespace std;

const string host = "123.60.25.237";
const string user = "root";
const string passwd = "";
const string db = "connect_demon";
const int port = 3306;

int main()
{
    //1、创建MySQL对象
    MYSQL* ms = mysql_init(nullptr);
    //2、连接数据库
    if(mysql_real_connect(ms, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr<<"数据库连接失败!"<

使用make命令生成可执行程序,运行后在MySQL中即可看到对应数据被成功删除。如下:

MySQL - 第14节 - MySQL使用C语言连接_第18张图片

修改数据库中的数据:

在调用mysql_query函数时,向MySQL服务器下发一条update SQL,如下。将该代码覆盖到前面的mysql_connect.cc文件中。

#include 
#include 
#include 
using namespace std;

const string host = "123.60.25.237";
const string user = "root";
const string passwd = "";
const string db = "connect_demon";
const int port = 3306;

int main()
{
    //1、创建MySQL对象
    MYSQL* ms = mysql_init(nullptr);
    //2、连接数据库
    if(mysql_real_connect(ms, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr<<"数据库连接失败!"<

使用make命令生成可执行程序,运行后在MySQL中即可看到对应数据被成功修改。如下:

MySQL - 第14节 - MySQL使用C语言连接_第19张图片

2.3.获取查询结果

获取查询结果:

• 对数据库中的数据进行增删改操作时,都只需要调用mysql_query向服务器下发对应的SQL请求。

• 而对数据库中的数据进行查询操作时,除了需要调用mysql_query向服务器下发对应的查询SQL,还需要获取查询结果。

获取查询结果的函数如下:

MYSQL_RES* mysql_store_result(MYSQL *mysql);

说明一下:

• 该函数会调用指定MySQL对象中对应的函数指针来获取查询结果,并将获取到的查询结果保存到MYSQL_RES变量中进行返回。
• 需要注意的是,MYSQL_RES变量的内存空间是malloc出来的,因此在使用完后需要调用free函数进行释放,否则会造成内存泄露(这个申请空间本身是函数自己申请的,本应由函数自己释放,因此一些版本的mysql进行了优化,不再需要我们手动的free释放了)。
MYSQL_RES变量中保存了查询得到的各种信息,其类型定义如下:

typedef struct st_mysql_res {
	my_ulonglong  row_count;
	MYSQL_FIELD	*fields;
	MYSQL_DATA	*data;
	MYSQL_ROWS	*data_cursor;
	unsigned long *lengths;		/* column lengths of current row */
	MYSQL		*handle;		/* for unbuffered reads */
    const struct st_mysql_methods *methods;
    MYSQL_ROW	row;			/* If unbuffered read */
    MYSQL_ROW	current_row;		/* buffer to current row */
    MEM_ROOT	field_alloc;
    unsigned int	field_count, current_field;
    my_bool	eof;			/* Used by mysql_fetch_row */
    /* mysql_stmt_close() had to cancel this result */
    my_bool       unbuffered_fetch_cancelled;
    void *extension;
} MYSQL_RES;

获取查询结果的行数:

获取查询结果的行数的函数如下:

my_ulonglong mysql_num_rows(MYSQL_RES *res);

说明一下:

• 该函数将会从指定的MYSQL_RES对象中,获取查询结果的行数。

获取查询结果的列数:

获取查询结果的列数的函数如下:

unsigned int mysql_num_fields(MYSQL_RES *res);

说明一下:

• 该函数将会从指定的MYSQL_RES对象中,获取查询结果的列数。

获取查询结果的列属性:

获取查询结果的列属性的函数如下:

MYSQL_FIELD* mysql_fetch_fields(MYSQL_RES *res);

说明一下:

• 该函数将会从指定的MYSQL_RES对象中,获取查询结果的列属性。

mysql_fetch_fields函数将会返回多个MYSQL_FIELD对象,每个MYSQL_FIELD对象中保存着对应列的各种列属性,其类型定义如下:

typedef struct st_mysql_field {
	char *name;                 /* Name of column */
	char *org_name;             /* Original column name, if an alias */
	char *table;                /* Table of column if column was a field */
	char *org_table;            /* Org table name, if table was an alias */
	char *db;                   /* Database for table */
	char *catalog;	      /* Catalog for table */
	char *def;                  /* Default value (set by mysql_list_fields) */
	unsigned long length;       /* Width of column (create length) */
	unsigned long max_length;   /* Max width for selected set */
	unsigned int name_length;
	unsigned int org_name_length;
	unsigned int table_length;
	unsigned int org_table_length;
	unsigned int db_length;
	unsigned int catalog_length;
	unsigned int def_length;
	unsigned int flags;         /* Div flags */
	unsigned int decimals;      /* Number of decimals in field */
	unsigned int charsetnr;     /* Character set */
	enum enum_field_types type; /* Type of field. See mysql_com.h for types */
	void *extension;
} MYSQL_FIELD;

获取查询结果中的一行数据:

获取查询结果中的一行数据的函数如下:

MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);

说明一下:

• 该函数将会从指定的MYSQL_RES对象中,获取查询结果中的一行数据。

MYSQL_ROW对象中保存着一行数据,这一行数据中可能包含多个字符串,对应就是这行数据中的多个列信息,因此MYSQL_ROW本质就是char**类型,其类型定义如下:

typedef char **MYSQL_ROW;		/* return data as array of strings */

• mysql_fetch_row会自动更新行数,即多次调用mysql_fetch_row函数,该函数每次会自动跳到下一行,获取下一行数据。

查询示例:

比如查询user表中的数据并进行打印输出,如下。将该代码覆盖到前面的mysql_connect.cc文件中。

#include 
#include 
#include 
using namespace std;

const string host = "123.60.25.237";
const string user = "frank";
const string passwd = "";
const string db = "connect_demon";
const int port = 3306;

int main()
{
    //1、获取MySQL实例(相当于给我们创建了一个MySQL句柄)
    MYSQL* ms = mysql_init(nullptr);
    //2、连接数据库
    if(mysql_real_connect(ms, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr<<"数据库连接失败!"<

使用make命令生成可执行程序,运行后在即可看到数据的查询结果。如下:

MySQL - 第14节 - MySQL使用C语言连接_第20张图片


3.自己实现一个MySQL命令行连接客户端

将如下代码写入前面的mysql_connect.cc文件。

#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

string host = "123.60.25.237"; 
string user = "root";
string passwd = "";
string db = "connect_demon";
unsigned int port = 3306;

int main()
{
    // 0. 初始化mysql对象
    MYSQL *msql = mysql_init(nullptr);
    if (msql == nullptr)
    {
        cerr << "mysql_init error" << endl;
        exit(1);
    }
    // 1. 登陆认证
    if (mysql_real_connect(msql, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
    {
        cerr << "mysql_real_connect error" << endl;
        exit(2);
    }
    mysql_set_character_set(msql, "utf8");
    cout << "mysql_real_connect success" << endl;

    char sql[1024];
    while (true)
    {
        printf("mysql> ");
        fgets(sql, sizeof sql, stdin); //'    select  * from user   ' 

        // 调用成功的时候,返回值是0, 否则就是1
        int n = mysql_query(msql, sql);
        if (strcasestr(sql, "select") && n == 0)
        {
            cout << "result: " << n << endl;
            // 对结果进行解析
            MYSQL_RES *res = mysql_store_result(msql);
            if (res == nullptr)
                exit(0);
            int rows = mysql_num_rows(res);
            int fields = mysql_num_fields(res);

            MYSQL_FIELD *fname = mysql_fetch_fields(res);

            for (int j = 0; j < fields; j++)
                cout << fname[j].name << "\t|\t";
            cout << endl;

            MYSQL_ROW line;
            for (int i = 0; i < rows; i++)
            {
                line = mysql_fetch_row(res); // 按行获取文件的内容,自动会更新行数
                for (int j = 0; j < fields; j++)
                    cout << line[j] << "\t|\t";
                cout << endl;
            }

            printf("%d rows in set\n", rows);
        }
        else
        {
            cout << "execl sql : " << sql << " done" << endl;
        }
    }
    // 关闭mysql对象
    mysql_close(msql);
    return 0;
}

使用make命令生成可执行程序,运行后即可发送sql指令,如下:

MySQL - 第14节 - MySQL使用C语言连接_第21张图片


4.MySQL图形化界面连接

• MySQL图形化界面连接的软件博主推荐Navicat,该软件收费(不收费的方法大家可以自己摸索)。

• 免费的MySQL图形化界面连接的软件博主推荐MySQL Workbench(该软件相比Navicat体验感差一些)。

注:这里不再介绍这些软件的下载和使用方法,大家可以自己去下载学习。

你可能感兴趣的:(MySQL数据库,mysql,数据库,linux,服务器,运维)