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

news/2024/10/20 6:44:35/

目录

mysql%20connect-toc" style="margin-left:0px;">mysql connect

介绍

开发环境

编译链接问题

编译

链接

接口介绍

初始化和销毁

mysql_init()-toc" style="margin-left:120px;">mysql_init()

句柄

mysql_close()-toc" style="margin-left:120px;">mysql_close()

链接数据库

mysql_real_connect()-toc" style="margin-left:120px;">mysql_real_connect()

参数

返回值

show processlist

mysql%E4%B8%8B%E8%BE%BE%E5%91%BD%E4%BB%A4-toc" style="margin-left:80px;">给mysql下达命令

mysql_query()-toc" style="margin-left:120px;">mysql_query()

参数

返回值

查询结果的获取

引入

mysql_store_result()-toc" style="margin-left:120px;">mysql_store_result()

参数

返回值

MYSQL_RES

读取结果集中的元数据

行数/列数

mysql_fetch_fields()%20--%20%E5%88%97%E4%BF%A1%E6%81%AF-toc" style="margin-left:120px;">mysql_fetch_fields() -- 列信息

type

获取结果集数据

访问行数据

mysql_fetch_row()%E2%80%8B%E2%80%8B%E2%80%8B%E2%80%8B%E2%80%8B%E2%80%8B%E2%80%8B-toc" style="margin-left:160px;">mysql_fetch_row()​​​​​​​

MYSQL_ROW

访问列数据 

mysql_fetch_field()-toc" style="margin-left:160px;">mysql_fetch_field()

设置编码格式

mysql_set_character_set()-toc" style="margin-left:120px;">mysql_set_character_set()

测试​​​​​​​

连接

命令行输入

代码

运行结果

输出查询结果

代码

运行结果


mysql%20connect" style="background-color:transparent;">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()" style="background-color:transparent;">mysql_init()

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

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

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

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

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

链接数据库

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

mysql_real_connect()" style="background-color:transparent;">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%E4%B8%8B%E8%BE%BE%E5%91%BD%E4%BB%A4">mysql下达命令

mysql_query()">mysql_query()

用于执行 SQL 查询

参数

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

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

查询结果的获取

引入

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

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

但查询不一样

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

如何获取结果呢?

  • mysql服务器执行查询操作后,会将满足条件的数据存放在服务器端的内存中,并形成结果集
  • 通过客户端调用特定接口,可以获取到结果集,并存储到特定结构
mysql_store_result()" style="background-color:transparent;">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()%20--%20%E5%88%97%E4%BF%A1%E6%81%AF" style="background-color:transparent;">mysql_fetch_fields() -- 列信息

返回一个MYSQL_FIELD类型的指针

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

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

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

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

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

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

获取结果集数据

访问行数据
mysql_fetch_row()%E2%80%8B%E2%80%8B%E2%80%8B%E2%80%8B%E2%80%8B%E2%80%8B%E2%80%8B">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()" style="background-color:transparent;">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()" style="background-color:transparent;">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.ppmy.cn/news/1540455.html

相关文章

基于python+dj+mysql的音乐推荐系统网页设计

音乐网站开发 如果你在学Python&#xff0c;需相关的【配套资料工具】作为研究[doge][脱单doge] 可以后台✉私信up主&#xff0c;发送&#x1f449;关键词【音乐】 本章以音乐网站项目为例&#xff0c;介绍Django在实际项目开发中的应用&#xff0c;该网站共分为6个功能模块分…

leetcode289:生命游戏

根据 百度百科 &#xff0c; 生命游戏 &#xff0c;简称为 生命 &#xff0c;是英国数学家约翰何顿康威在 1970 年发明的细胞自动机。 给定一个包含 m n 个格子的面板&#xff0c;每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态&#xff1a; 1 即为 活细胞 &am…

宝塔PHP8.1安装fileinfo拓展失败解决办法

在宝塔面板中安装PHP8.1后&#xff0c;安装fileinfo扩展一直安装不上&#xff0c;查看日志有报错&#xff0c;于是手动来安装也报错。 宝塔报错&#xff1a; 手动命令行编译安装同&#xff0c;也有报错 cd /www/server/php/81/src/ext/fileinfo/ make distclean ./configure …

sharding sphere 加解密功能 like语句 SQL 解析报错

问题描述 应用在使用 sharding sphere 来实现加密后&#xff0c;对于 like sql 语句解析抛异常&#xff0c;异常信息如下&#xff1a; sharding sphere 版本 5.3.2 xml 文件SQL 语句&#xff1a; <select id"countSchoolByStatus" parameterType"java.la…

word取消自动单词首字母大写

情况说明&#xff1a;在word输入单词后首字母会自动变成大写 &#xff08;1&#xff09;点击菜单栏文件 &#xff08;2&#xff09;点击“更多”——>“选项” &#xff08;3&#xff09;点击“校对”——>“自动更正选项” &#xff08;4&#xff09;取消“句首字母大写…

vue3 笔记-插槽

结构类似的模块&#xff0c;我们可以考虑用插槽&#xff0c;以便后续复用&#xff1a; 代码&#xff1a; 1.插槽 <script setup> defineProps({title: {required: true,type: String},number: {required: true,type: Number} }) </script><template><d…

【STL】string类的使用

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;C、STL 目录 string类的介绍--为什么学习string类 一、string类的默认成员函数 构造函数(constructor) 析构函数(destructor) 赋值运算符重载operator 二…

【漏洞复现】畅捷通T+ FileUploadHandler.ashx 任意文件上传漏洞

免责声明: 本文旨在提供有关特定漏洞的信息,以帮助用户了解潜在风险。发布此信息旨在促进网络安全意识和技术进步,并非出于恶意。读者应理解,利用本文提到的漏洞或进行相关测试可能违反法律或服务协议。未经授权访问系统、网络或应用程序可能导致法律责任或严重后果…