【MySQL】C/C++连接MySQL客户端,MySQL函数接口认知,图形化界面进行连接

三问走天下 2024-09-04 10:35:10 阅读 81

【MySQL】C/C++引入MySQL客户端

安装mysqlclient库mysql接口介绍初始化mysql_init链接数据库mysql_real_connect下发mysql命令mysql_query获取出错信息mysql_error获取执行结果mysql_store_result获取结果行数mysql_num_rows获取结果列数mysql_num_fields判断结果列数mysql_field_countmysql_num_fields 与 mysql_field_count的区别

获取列名mysql_fetch_fields获取结果内容mysql_fetch_row获取列当前列的长度mysql_fetch_lengths释放结果集mysql_freer_result关闭mysql链接mysql_close

整体测试代码图形化界面连接下载workbenchUbuntu提供mysql权限workbench图形化连接

安装mysqlclient库

安装mysql

Ubuntu安装MySQL8.0安装连接库

在Ubuntu上使用C/C++连接MySQL 8.0,你需要使用MySQL官方提供的连接器库,即libmysqlclient。

<code>sudo apt-install libmysqlclient-dev

执行时需要连接这个库

gcc -o xxx yyy -lmysqlclient

mysql接口介绍

相关具体函数可到mysql官网中去查询链接: 直接点击查看所有8.0版本函数

找到官网

在这里插入图片描述

找到CAPI

在这里插入图片描述

查看所有函数

在这里插入图片描述

初始化mysql_init

要使用库,必须先进行初始化!

函数原型:

<code>MYSQL *mysql_init(MYSQL *mysql)

分配或初始化适用于 mysql_real_connect() 的 MYSQL 对象。如果 mysql 为 NULL 指针,则该函数分配、初始化并返回一个新对象。否则,将初始化该对象并返回该对象的地址。如果 mysql_init() 分配了一个新对象,则在调用 mysql_close() 关闭连接时将释放该对象。

在非多线程环境中,mysql_init() 会根据需要自动调用 mysql_library_init()。但是,mysql_library_init() 在多线程环境中不是线程安全的,因此 mysql_init() 也不是。在调用 mysql_init() 之前,要么在生成任何线程之前调用 mysql_library_init(),要么使用互斥锁来保护 mysql_library_init() 调用。这应该在任何其他客户端库调用之前完成。

所以一般mysql_int()的这个里面的参数都是null;

返回值:

已初始化的 MYSQL* 处理程序。如果内存不足以分配新对象,则返回 NULL。

链接数据库mysql_real_connect

初始化完毕之后,必须先链接数据库,在进行后续操作。(mysql网络部分是基于TCP/IP的)

函数原型:

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 client_flag)

//建立好链接之后,获取英文没有问题,如果获取中文是乱码:

//设置链接的默认字符集是utf8,原始默认是latin1

mysql_set_character_set(myfd, "utf8");

参数解析:

第一个参数 MYSQL是 C api中一个非常重要的变量(mysql_init的返回值),里面内存非常丰富,有port,dbname,charset等连接基本参数。它也包含了一个叫 st_mysql_methods的结构体变量,该变量里面保存着很多函数指针,这些函数指针将会在数据库连接成功以后的各种数据操作中被调用。host:连接的主机名/ipuser:连接的用户名passwd:连接数据库的密码db:连接数据库的名称port:连接数据库的端口号unix_socket:连接数据库的连接方式(一般直接设置为NULL即可)client_flag:这个也是一般直接设置为0即可

返回值:

如果连接成功,则返回 MYSQL* 连接处理程序;如果连接失败,则返回 NULL。对于成功的连接,返回值与第一个参数的值相同。

int main()

{ -- -->

// std::cout << "mysql client version" << mysql_get_client_info()<< std::endl;

MYSQL* my = mysql_init(nullptr);

if (my == NULL)

{

std::cerr << "mysql init error..." << std::endl;

return 1;

}

if (mysql_real_connect(my,host.c_str(), user.c_str(), password.c_str(), db.c_str(), port, NULL, 0) == nullptr)

{

std::cerr << "mysql connect error..." << std::endl;

return 2;

}

std::cout << "mysql connect success..." << std::endl;

sleep(10); // 这里我们不急着关闭,可以先看一下现象

mysql_close(my);

return 0;

}

在这里插入图片描述

从上面的结果我们也可以看出是连接成功的了。

下发mysql命令mysql_query

函数原型

<code>int mysql_query(MYSQL *mysql, const char *stmt_str)

执行以空字符结尾的字符串 stmt_str 指向的 SQL 语句。通常,该字符串必须由一条 SQL 语句组成,且不带终止分号 ( ; ) 或 \g。如果已启用多语句执行,则该字符串可以包含多条以分号分隔的语句。

mysql_query() 不能用于包含二进制数据的语句;您必须使用 mysql_real_query()。(二进制数据可能包含 \0 字符,mysql_query() 将其解释为语句字符串的结尾。)

参数

第一个参数时mysql_init的返回值,第二个参数时要执行的SQL语句

返回值

零表示成功。非零值表示发生错误。

案例

创建一张新表

std::string sql = "create table test(id int primary key, name varchar(20))";

if (mysql_query(my, sql.c_str()) != 0)

{ -- -->

std::cerr << "mysql query error..." << std::endl;

std::cout << mysql_error(my) <<std::endl;

return 3;

}

std::cout << "mysql query success..." << std::endl;

Database changed

mysql> show tables;

+----------------+

| Tables_in_conn |

+----------------+

| test |

+----------------+

1 row in set (0.00 sec)

mysql> desc test;

+-------+-------------+------+-----+---------+-------+

| Field | Type | Null | Key | Default | Extra |

+-------+-------------+------+-----+---------+-------+

| id | int | NO | PRI | NULL | |

| name | varchar(20) | YES | | NULL | |

+-------+-------------+------+-----+---------+-------+

2 rows in set (0.01 sec)

获取出错信息mysql_error

函数原型:

const char mysql_error(MYSQL *mysql);

对于 mysql 指定的连接,mysql_error() 返回一个以空字符结尾的字符串,其中包含最近调用的失败的 API 函数的错误消息。如果函数未失败,mysql_error() 的返回值可能是前一个错误或一个空字符串(表示没有错误)。

经验法则是,所有必须向服务器询问信息的函数如果成功则重置 mysql_error()。

参数解析

参数就是mysql_init的返回值

返回值

描述错误的以空字符结尾的字符串。如果没有发生错误,则为空字符串。

案例

我们再次执行mysql_query的命令,创建一张表

在这里插入图片描述

获取执行结果mysql_store_result

函数原型:

<code>MYSQL_RES *mysql_store_result(MYSQL *mysql)

该函数会调用MYSQL变量中的st_mysql_methods中的 read_rows 函数指针来获取查询的结果。同时该函数会返回MYSQL_RES 这样一个变量,该变量主要用于保存查询的结果。同时该函数malloc了一片内存空间来存储查询过来的数据,所以我们一定要记的 free(result),不然是肯定会造成内存泄漏的。 执行完mysql_store_result以后,其实数据都已经在MYSQL_RES 变量中了,下面的api基本就是读取MYSQL_RES 中的数据。

在这里插入图片描述

参数解析

参数就是mysql_init的返回值

<code>typedef struct MYSQL_RES { -- -->

uint64_t row_count;

MYSQL_FIELD *fields;

struct MYSQL_DATA *data;

MYSQL_ROWS *data_cursor;

unsigned long *lengths; /* column lengths of current row */

MYSQL *handle; /* for unbuffered reads */

const struct MYSQL_METHODS *methods;

MYSQL_ROW row; /* If unbuffered read */

MYSQL_ROW current_row; /* buffer to current row */

struct MEM_ROOT *field_alloc;

unsigned int field_count, current_field;

bool eof; /* Used by mysql_fetch_row */

/* mysql_stmt_close() had to cancel this result */

bool unbuffered_fetch_cancelled;

enum enum_resultset_metadata metadata;

void *extension;

} MYSQL_RES;

返回值

指向包含结果的 MYSQL_RES 结果结构的指针。如果语句未返回结果集或发生错误,则为 NULL。要确定是否发生错误,请检查 mysql_error() 是否返回非空字符串、mysql_errno() 是否返回非零,或 mysql_field_count() 是否返回零。

案例

mysql> select * from test;

+----+--------+

| id | name |

+----+--------+

| 1 | 张三 |

| 2 | 李四 |

| 3 | 王五 |

+----+--------+

3 rows in set (0.00 sec)

uint64_t rows = mysql_num_rows(res); // 获取行

unsigned int cols = mysql_num_fields(res); // 获取列

std::cout << "行:" << rows << ",列" << cols << std::endl;

在这里插入图片描述

获取结果行数mysql_num_rows

函数原型

<code>uint64_t mysql_num_rows(MYSQL_RES *result)

参数

参数是mysq_stroe_result的返回值。

返回值

返回结果集中的行数

获取结果列数mysql_num_fields

函数原型:

unsigned int mysql_num_fields(MYSQL_RES *result)

您可以从指向结果集或连接处理程序的指针获取列数。如果 mysql_store_result() 或 mysql_use_result() 返回 NULL(因此您没有结果集指针),则可以使用连接处理程序。在这种情况下,您可以调用 mysql_field_count() 来确定 mysql_store_result() 是否应该产生非空结果。这使客户端程序能够采取适当的操作,而无需知道查询是否为 SELECT(或类似 SELECT)语句。此处显示的示例说明了如何完成此操作。

参数解析

参数就是mysql_store_result的返回值

返回值

返回结果集中的列数,表示结果集中列数的无符号整数。

判断结果列数mysql_field_count

函数原型

unsigned int mysql_field_count(MYSQL *mysql)

此函数的正常使用是当 mysql_store_result() 返回 NULL(因此您没有结果集指针)时。在这种情况下,您可以调用 mysql_field_count() 来确定 mysql_store_result() 是否应该产生非空结果。这使客户端程序能够采取适当的操作,而无需知道查询是否是 SELECT(或类似 SELECT)语句。此处显示的示例说明了如何执行此操作

参数

参数就是mysql_init的返回值

返回值

返回连接上最近查询的列数。

mysql_num_fields 与 mysql_field_count的区别

参数区别

首先就是mysql_num_fields的参数是mysql_store_result的返回值,而mysql_field_count的参数则是mysql_init的返回值。

用途区别

虽然这两个函数返回的都是字段列的个数。但是他们的作用以及查询的条件也是不一样的。mysql_field_count函数是返回作用在连接上的最近查询的列数,它的主要用途是在mysql_store_result()返回NULL(因而没有结果集指针)时,通过调用mysql_field_count()来判断mysql_store_result()是否应生成非空结果。而mysql_num_fields是根据mysql_store_result的返回值来查询列数的。因为像insert,update,select作用在mysql_store_result函数时是没有返回值的,所以这个时候mysql_store_result返回的就是NULL,而mysql_num_fields函数内部肯定是要对mysql_store_result的返回值做解引用的,这个时候对NULL做解引用显然会出现错误,所以需要加以判断。

综上所述

其实mysql_field_count更像时起到了一个判断的作用,而mysql_num_fields才像是一样获取列数的函数。两者在使用场景和返回值上有所区别,前者更侧重于查询的结果判断,而后者则提供具体的字段信息‌

mysql官网上的示例

if (mysql_query(&mysql,query_string))

{ -- -->

// error

}

else // query succeeded, process any data returned by it

{

result = mysql_store_result(&mysql);

if (result) // there are rows

{

num_fields = mysql_num_fields(result);

// retrieve rows, then call mysql_free_result(result)

}

else // mysql_store_result() returned nothing; should it have?

{

if(mysql_field_count(&mysql) == 0)

{

// query does not return data

// (it was not a SELECT)

num_rows = mysql_affected_rows(&mysql);

}

else // mysql_store_result() should have returned data

{

fprintf(stderr, "Error: %s\n", mysql_error(&mysql));

}

}

}

注意事项

select 0------ 假设执行了select 0 查询id等于0这条语句,假设没有id=0的这条语句

select 0---count_fields is 2

select 0---num_fields is 2

select 0---num_rows is 0

从上面我们也可以发现,就算我们查找的id=0的行数=0,也就是没有这条记录,但是mysql_field_count和mysql_num_fields显示的都不是0(假设列字段为2)都显示为2。所以我们就可以得出一结论。在执行mysql_store_result时有两个结果:第一种结构就是执行delete,update,insert这样的语句时,mysql_store_result返回的是NULL,此时可以用mysql_field_count来进行判断。第二就是执行select,show这样的语句时一定是有返回值的,但是返回的记录也就是行可以是为0的,也可以不为0,这就有点像一张表可以没有内容,但是一定会有表头。

获取列名mysql_fetch_fields

函数原型:

MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result)

返回结果集的所有 MYSQL_FIELD 结构的数组。每个结构为结果集的一列提供字段定义。也就是返回列属性。

参数解析

参数就是mysq_store_result的返回值

typedef struct 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_FIELD 结构数组。如果结果集没有元数据,则为 NULL。每个结构为结果集的一列提供字段定义。

案例

MYSQL_FIELD *fields = mysql_fetch_fields(res);

for (int i = 0; i < cols; i++)

{

std::cout << fields[i].name << " ";

}

std::cout << std::endl;

在这里插入图片描述

获取结果内容mysql_fetch_row

函数原型:

<code>MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)

它会返回一个MYSQL_ROW变量,MYSQL_ROW其实就是char **.就当成一个二维数组来用吧。

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

参数解析

参数就是mysql_store_result的返回值

返回值

描述错误的以空字符结尾的字符串。如果没有发生错误,则为空字符串。

案例

其实这个函数我们可以看作是C++的迭代器,他会自动进行往后遍历

MYSQL_ROW line;

for (int i = 0; i < rows; i++)

{ -- -->

line = mysql_fetch_row(res);

for (int j = 0; j < cols; j++)

{

std::cout << line[j] << " ";

}

std::cout << std::endl;

}

在这里插入图片描述

获取列当前列的长度mysql_fetch_lengths

函数原型

<code>unsigned long *mysql_fetch_lengths(MYSQL_RES *result)

返回结果集中当前行的列的长度。如果您计划复制字段值,此长度信息对于优化也很有用,因为您可以避免调用 strlen()。此外,如果结果集包含二进制数据,则必须使用此函数来确定数据的大小,因为 strlen() 对于任何包含空字符的字段都会返回不正确的结果。

mysql_fetch_lengths() 仅对结果集的当前行有效。如果在调用 mysql_fetch_row() 之前或在检索结果中的所有行之后调用它,它将返回 NULL。

参数

参数就是mysql_store_result的返回值

返回值

表示每列大小的无符号长整数数组(不包括任何终止空字节)。如果发生错误,则返回 NULL。

案例

//必须先调用了mysql_fetch_row后才能调用,他仅对结果集的当前行后效,一般都是先到用完mysql_fetch_row再调用

unsigned long *lengths = mysql_fetch_lengths(res);

if (rows)

{ -- -->

for (int i = 0; i < cols; i++)

{

printf("Column %u is %lu bytes in length.\n", i, lengths[i]);

}

std::cout << std::endl;

}

在这里插入图片描述

释放结果集mysql_freer_result

<code>void mysql_free_result(MYSQL_RES *result)

mysql_free_result() 释放由 mysql_store_result()、mysql_use_result()、mysql_list_dbs() 等为结果集分配的内存。处理完结果集后,必须通过调用 mysql_free_result() 释放其使用的内存。

所以一般再时使用完结果集后要释放它,防止内存泄漏。

关闭mysql链接mysql_close

函数原型:

void mysql_close(MYSQL *mysql)

关闭先前打开的连接。如果处理程序是由 mysql_init() 或 mysql_connect() 自动分配的,mysql_close() 还会释放由 mysql 指向的连接处理程序。关闭后请勿使用该处理程序。

参数解析

参数就是mysql_init的返回值

整体测试代码

#include <iostream>

#include <mysql/mysql.h>

#include <string>

#include <unistd.h>

// const std::string host = "127.0.0.1";

const std::string host = "localhost";

const std::string user = "chuyang";

const std::string password = "123456";

const std::string db = "conn";

const unsigned int port = 3306;

int main()

{ -- -->

// 1. 初始化

MYSQL *my = mysql_init(nullptr);

if (my == NULL)

{

std::cerr << "mysql init error..." << std::endl;

return 1;

}

// 2. 数据库连接

if (mysql_real_connect(my, host.c_str(), user.c_str(), password.c_str(), db.c_str(), port, NULL, 0) == nullptr)

{

std::cerr << "mysql connect error..." << std::endl;

return 2;

}

// 3. 设置字符集

mysql_set_character_set(my, "utf8");

std::cout << "mysql connect success..." << std::endl;

// 4. 对数据库进行操作

std::string sql = "create table if not exists test(id int primary key, name varchar(20))";

if (mysql_query(my, sql.c_str()) != 0)

{

std::cerr << "mysql query error..." << std::endl;

std::cout << mysql_error(my) << std::endl;

return 3;

}

std::cout << "mysql query success..." << std::endl;

sql = "select * from test";

if (mysql_query(my, sql.c_str()) != 0)

{

std::cerr << "mysql query error..." << std::endl;

std::cout << mysql_error(my) << std::endl;

return 3;

}

// 5. 获取结果(主要是针对select)

MYSQL_RES *res = mysql_store_result(my);

if (nullptr == res)

{

std::cerr << "mysql stroe result error..." << std::endl;

std::cout << mysql_error(my) << std::endl;

return 4;

}

std::cerr << "mysql stroe result success..." << std::endl;

// 6. 获取结果的列数,和行数

uint64_t rows = mysql_num_rows(res); // 获取行

unsigned int cols = mysql_num_fields(res); // 获取列

std::cout << "行:" << rows << ",列" << cols << std::endl;

// 7. 拿到结果

// 获取属性

MYSQL_FIELD *fields = mysql_fetch_fields(res);

for (int i = 0; i < cols; i++)

{

std::cout << fields[i].name << " ";

}

std::cout << std::endl;

// 获取内容

MYSQL_ROW line;

for (int i = 0; i < rows; i++)

{

line = mysql_fetch_row(res);

for (int j = 0; j < cols; j++)

{

std::cout << line[j] << " ";

}

std::cout << std::endl;

}

//必须先调用了mysql_fetch_row后才能调用,他仅对结果集的当前行后效,一般都是先到用完mysql_fetch_row再调用

unsigned long *lengths = mysql_fetch_lengths(res);

if (rows)

{

for (int i = 0; i < cols; i++)

{

printf("Column %u is %lu bytes in length.\n", i, lengths[i]);

}

std::cout << std::endl;

}

// 8. 释放结果集

mysql_free_result(res);

// 9. 关闭连接

mysql_close(my);

return 0;

}

图形化界面连接

这里用的是workbanch进行的连接

下载workbench

进入MySQL官网

在这里插入图片描述

点击社区版

在这里插入图片描述

下载workbench

在这里插入图片描述

Ubuntu提供mysql权限

因为Ubuntu下我们的mysql不推荐给root账号使用登录,而是创建普通用户让其登陆。

创建普通用户,并给予权限

<code>mysql> create user 'chuyang'@'%' identified by '密码';

mysql> grant all on conn.* to 'chuyang'@'%';

mysql> select User, Host from user;

+------------------+-----------+

| User | Host |

+------------------+-----------+

| chuyang | % |

| mysql.infoschema | localhost |

| mysql.session | localhost |

| mysql.sys | localhost |

| root | localhost |

+------------------+-----------+

5 rows in set (0.00 sec)

workbench图形化连接

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。