当前位置: 首页 > news >正文

mysql connect -- C api编译链接问题,接口介绍(初始化和销毁,连接,执行sql语句,获取结果集的元数据和数据,设置编码格式)

目录

mysql connect

介绍

开发环境

编译链接问题

编译

链接

接口介绍

初始化和销毁

mysql_init()

句柄

mysql_close()

链接数据库

mysql_real_connect()

参数

返回值

show processlist

给mysql下达命令

mysql_query()

参数

返回值

查询结果的获取

引入

mysql_store_result()

参数

返回值

MYSQL_RES

读取结果集中的元数据

行数/列数

mysql_fetch_fields() -- 列信息

type

获取结果集数据

访问行数据

mysql_fetch_row()​​​​​​​

MYSQL_ROW

访问列数据 

mysql_fetch_field()

设置编码格式

mysql_set_character_set()

测试​​​​​​​

连接

命令行输入

代码

运行结果

输出查询结果

代码

运行结果


mysql connect

介绍

无论是使用mysql命令行式客户端,还是图形化界面,还是使用c/c++语言连接数据库

  • 本质上没有差别,都是客户端的一种实现形式
  • 都是要和mysql服务器建立连接并登录

我们下面介绍用C api来连接数据库的方式

  • 因为好理解(c++ api在C api的基础上进行了封装)
  • 虽然是C api,但因为c++兼容c,所以我们依然可以使用c++语言来编写代码

开发环境

其实在下载mysql服务时,看似只下载了mysql-community-server,实际上把服务器,客户端,开发包什么的都下载好了

  • 所以我们这里可以直接使用

开发包在哪呢?

  • ls /usr/include/mysql 头文件
  • /usr/lib64/mysql 或者/lib64/mysql 库文件
  • (我这里不知道为啥两个路径下都有)

如果没有,就单独安装mysql-devel

编译链接问题

编译

编译时需要指明我们使用了mysql第三方库 

因为我们要使用mysql.h中的函数,如果头文件中不写mysql/mysql.h,只写mysql.h,编译器会找不到头文件在哪,就需要添加-I选项

  • 因为系统路径只包括/usr/include的部分,而mysql.h在其下子目录中,所以需要带上上级目录名

链接

虽然文件放在了编译器可以查找的路径下,但编译器无法自主寻找,并且也不知道应该链接哪个库

  • 所以,要添加-L/lib64/mysql -lmysqlclient
  • (哪个路径下有那些库文件,-L就带上哪个路径)

如果运行时报错,就将缺少的动态库路径添加进系统配置文件/环境变量中

  • 比如这里的/etc/ld.so.conf.d/,它用于存放动态链接库的配置文件
  • 因为我这里有,所以就不添加了:

接口介绍

在mysql官网中可以查看接口手册

初始化和销毁

mysql_init()

初始化一个MYSQL结构体,以便在后续操作中使用

  • 参数一般写成NULL即可
  • 返回值其实是一个句柄,和打开文件后返回的FILE类型的指针一样
  • 如果返回NULL,表示初始化失败
句柄

表示对系统资源(如文件、窗口、数据库连接等)的引用

  • 句柄本质上是一个标识符,通常是一个整数或指针
  • 它允许程序在不直接操作底层资源的情况下,进行资源的管理和操作
mysql_close()

关闭与数据库的连接,并释放与该连接相关的资源

链接数据库

连接mysql服务器的前提是,要先有一个用户和一个数据库

mysql_real_connect()
MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *password, const char *dbname, unsigned int port, const char *unix_socket, unsigned long client_flag);
参数

返回值
  • 如果成功,会将传入的那个指针返回 -- 类似于c接口中做字符串截取/拷贝时,会返回原始子串
  • 失败返回NULL
show processlist

是 MySQL 中的一个 SQL 命令

  • 用于显示当前数据库服务器中所有正在执行的线程信息
  • 可以通过在c/c++程序中调用sleep(),让我们的程序保持和服务器的连接状态,然后在mysql中查看连接情况

给mysql下达命令

mysql_query()

用于执行 SQL 查询

参数

传入MYSQL结构的指针 和 要执行的 SQL 查询字符串

  • 这里传入的参数中,sql语句不需要加分号或者\G
返回值

查询结果的获取

引入

因为mysql有事务的存在,即使有多个客户端同时操作表中数据,也不会出问题

  • 所以,只要我们提供正确的sql语句,就能完成增删改的操作

但查询不一样

  • 当我们传入select操作,函数返回值是0,代表操作成功执行
  • 但是我们并没有拿到结果

如何获取结果呢?

  • 当mysql服务器执行查询操作后,会将满足条件的数据存放在服务器端的内存中,并形成结果集
  • 通过客户端调用特定接口,可以获取到结果集,并存储到特定结构
mysql_store_result()

用于获取查询结果的函数

参数

该函数会调用MYSQL变量中的st_mysql_methods中的 read_rows函数指针来获取查询的结果

返回值

  • 同时,该函数malloc了一片内存空间来存储查询结果数据
  • 所以我们一定要释放掉这块空间,不然是肯定会造成内存泄漏的 -- mysql内部提供了mysql_free_result()来帮助我们释放掉这块空间
MYSQL_RES

将结果集保存在MYSQL_RES结构中,是为了方便我们进行二次处理

如何进行二次处理?

  • 插入的时候mysql分了很多类型,但将数据读出来的时候,全都当做字符串来处理

实际上,可以把MYSQL_RES看作是以下面这种方式放置数据的(二维数组):

  • 按行遍历就是拿出char**,按列遍历就是拿出每行中的char*
  • 这样对数据做分析,就变成了对这个结构做分析

读取结果集中的元数据

行数/列数

mysql_fetch_fields() -- 列信息

返回一个MYSQL_FIELD类型的指针

  • 也就是一个MYSQL_FIELD类型的数组

每一列的信息以结构体的方式保存起来,一个数组里面就包含了该表所有列

  • org -- 表示原生(因为可能会给列起别名)
type

这个枚举类型定义了mysql中的数据类型

因为mysql中把数据都当做字符串

  • 当我们提取出来之后,就可以根据它们的原有类型进行类型转换,即可恢复类型

获取结果集数据

访问行数据
mysql_fetch_row()​​​​​​​

用于从结果集中获取下一行数据,返回一个指向该行的指针

  • 类似于迭代器的作用(调用一次就返回当前行,并自动指向下一行)
  • 只是需要我们自行控制遍历次数(根据行数)

MYSQL_ROW

为了更好地支持遍历,mysql提供了MYSQL_ROW这个结构

  • 表示查询结果集中的一行数据
  • 而MYSQL_ROW=char**,其实就是像上面图中画的一样往下遍历

 

访问列数据 

当我们成功拿到一行后,就可以像对待字符串数组一样,用数组下标拿到每一列

  • 列数就是元素个数
  • while ((row = mysql_fetch_row(res)) != NULL) {// 访问第一列printf("First column: %s\n", row[0]);
    }

mysql_fetch_field()

获取结果集中当前列的元数据

  • 和迭代器类似,每次可以获取一列信息

while ((field = mysql_fetch_field(res)) != NULL) {printf("Column name: %s, Type: %d\n", field->name, field->type);
}

设置编码格式

当我们插入中文字符时,mysql内部存入的是乱码

  • 出现乱码的原因一定是双方对编码格式没有达成一致
  • 而mysql我们已经配置过,使用的就是utf8的格式,那就只能是我们代码这边编码格式有问题

在链接mysql时,需要设置字符集 -- mysql_set_character_set()

  • 字符集和编码格式紧密相关,设置字符集通常意味着也设置了相应的编码格式
  • 原始默认字符集是latin1
mysql_set_character_set()

测试​​​​​​​

连接

我们先在mysql创建一张表

  • ​​​​​​​

然后测试我们是否能通过cpp程序控制mysql

#include <iostream>
#include <mysql/mysql.h>int main()
{MYSQL *mysql = mysql_init(nullptr);mysql = mysql_real_connect(mysql, "ip地址", "mufeng", "599348181", "conn", 3306, nullptr, 0);if (nullptr == mysql){std::cout << "connect failed\n";exit(1);}std::cout<<"connect success\n";mysql_close(mysql);return 0;
}

可以看到我们连接成功:

  • 注意这里,我应该是在本机上连接的(vscode和xshell上都是远程连接同一个云服务器),但用户如果设置localhost,依然没法连接成功,不知道为啥
  • 总之如果不行的话,用户还是设置成允许所有主机登录吧

命令行输入

我们可以设置以命令行输入的形式,将输入内容作为sql语句让mysql去执行,并且模拟mysql的行为

  • 当然,我们实际进行开发的时候,直接调用接口就行,不用整什么命令行
  • 因为本身mysql就有客户端,没必要我们也弄一个

以及要注意设置编码格式

代码
#include <iostream>
#include <string>
#include <mysql/mysql.h>int main()
{MYSQL *mysql = mysql_init(nullptr);mysql = mysql_real_connect(mysql, "ip地址", "mufeng", "599348181", "conn", 3306, nullptr, 0);if (nullptr == mysql){std::cout << "connect failed\n";exit(1);}std::cout << "connect success\n";mysql_set_character_set(mysql, "utf8");std::string sql;std::cout << "mysql>";std::cout.flush();while (std::getline(std::cin, sql)){if (sql == "quit"){std::cout << "bye\n";break;}int ret = mysql_query(mysql, sql.c_str());if (ret == 0){std::cout << sql << " success\n";}else{std::cout << mysql_error(mysql) << std::endl;}std::cout << "mysql>";std::cout.flush();}mysql_close(mysql);return 0;
}
运行结果

可以看见,我们通过自己编写的客户端向表中插入数据,在mysql下是可以看到更改的

 插入中文也可以:

输出查询结果

如果我们不进行特殊处理,是无法看见查询结果的:

  • ​​​​​​​
代码
#include <iostream>
#include <string>
#include <mysql/mysql.h>void client(MYSQL *mysql)
{std::string sql;std::cout << "mysql>";std::cout.flush();while (std::getline(std::cin, sql)){if (sql == "quit"){std::cout << "bye\n";break;}int ret = mysql_query(mysql, sql.c_str());if (ret == 0){std::cout << sql << " success\n";}else{std::cout << mysql_error(mysql) << std::endl;}std::cout << "mysql>";std::cout.flush();}
}void select_test(MYSQL *mysql)
{std::string sql;sql = "select * from test";int ret = mysql_query(mysql, sql.c_str());if (ret == 0){MYSQL_RES *res = mysql_store_result(mysql);if (res == nullptr){std::cout << "mysql_store_result failed\n";}else{int row_num = mysql_num_rows(res);int field_num = mysql_num_fields(res);// 打印列名MYSQL_FIELD *field;while ((field = mysql_fetch_field(res)) != NULL){std::cout << field->name << " ";}std::cout << std::endl;// 打印表数据for (int i = 0; i < row_num; ++i){MYSQL_ROW row = mysql_fetch_row(res);for (int j = 0; j < field_num; j++){std::cout << row[j] << " ";}std::cout << std::endl;}}}else{std::cout << mysql_error(mysql) << std::endl;}
}int main()
{MYSQL *mysql = mysql_init(nullptr);mysql = mysql_real_connect(mysql, "ip地址", "mufeng", "599348181", "conn", 3306, nullptr, 0);if (nullptr == mysql){std::cout << "connect failed\n";exit(1);}std::cout << "connect success\n";mysql_set_character_set(mysql, "utf8");// client(mysql);select_test(mysql);mysql_close(mysql);return 0;
}
运行结果

可以看到,我们成功模拟出mysql中打印查询结果的样式,只是少了表格结构:


 


http://www.mrgr.cn/news/54251.html

相关文章:

  • 聚铭网络入选工信部《工业互联网与电力行业融合应用参考指南》推荐企业
  • 什么是 SQL 注入攻击?如何防止 SQL 注入?
  • 商品详情API接口调用流程
  • React是如何工作的?
  • 【植物识别系统】Python+人工智能+深度学习+卷积神经网络算法+TensorFlow+算法模型+Django网页界面平台
  • ab命令深入解析:ApacheBench性能测试工具
  • Python Logging 模块
  • Unexpected error: java.security.InvalidAlgorithmParameterException
  • 关于office中的word文档图片替换问题
  • MySQL程序介绍<二>
  • freeswitch-esl 进行强拆控制
  • 【代码随想录Day46】单调栈Part01
  • 探索计算机技术的无限可能:从基础到前沿的深度之旅
  • PCL 点云配准 非线性加权最小二乘优化的点到面ICP算法(精配准)
  • 使用 NVBit 进行内存访问跟踪指南
  • 希尔(shell)排序
  • 深入理解Reactor核心概念
  • 【部署篇】RabbitMq-02单机模式部署
  • [H264]x264_encoder_headers函数
  • 第六十一周周报 MDSSSA-GNN
  • 计算机毕业设计Spark+大模型高考分数线预测 知识图谱高考志愿推荐系统 高考数据分析可视化 高考大数据 大数据毕业设计
  • 【洛谷】P1856
  • 【H2O2|全栈】WPS/Office系列有哪些好用的快捷方式?
  • Javaweb基础-axios
  • 学习虚幻C++开发日志——TSet
  • 推荐系统 # 二、推荐系统召回:协同过滤 ItemCF/UserCF、离散特征处理、双塔模型、自监督学习、多路召回、曝光过滤