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

news2024/11/28 9:44:26

目录

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.coloradmin.cn/o/2219036.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HarmonyOS NEXT 应用开发实战(七、知乎日报轮播图的完整实现)

在今天的博文中&#xff0c;我们将深入探讨如何在 HarmonyOS NEXT 中使用 ArkUI 实现一个轮播图组件。我们将通过一个示例代码来演示这个完整的过程&#xff0c;其中包含获取数据、管理数据源以及渲染组件等多个部分。 先来看下最终实现效果&#xff1a; 项目准备 首先&#…

JMeter之mqtt-jmeter 插件介绍

前言 mqtt-jmeter插件是JMeter中的一个第三方插件&#xff0c;用于支持MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;协议的性能测试。MQTT是一种轻量级的发布/订阅消息传输协议&#xff0c;广泛应用于物联网和传感器网络中。 一、安装插件 mqtt-jmeter项目…

【智能算法应用】雪消融优化算法求解二维路径规划问题

摘要 本文研究了雪消融优化算法在二维路径规划问题中的应用。该算法基于自然界中雪消融现象的模拟&#xff0c;通过优化策略寻找无人机路径的最优解。实验结果表明&#xff0c;该算法在路径规划中表现出较高的效率和收敛速度&#xff0c;能够有效地避开障碍物并找到代价最低的…

基于SpringBoot+Vue的校园周边美食探索及分享平台的设计与实现(带文档)

基于SpringBootVue的校园周边美食探索及分享平台的设计与实现&#xff08;带文档) 开发语言:Java数据库:MySQL技术:SpringBootMyBatisVue等工具:IDEA/Ecilpse、Navicat、Maven 源码 校园周边美食探索及分享平台是一个旨在为校园用户提供便捷的美食发现和分享服务的系统。该平…

我的JAVA项目构建

1.Maven maven就是pip 设置maven下载的的jar包位置 换源 下载插件maven-search 配置dependency 2.Tomcat 设置环境变量JAVA_HOME 设置编码方式 方框就是路径的前缀 3.Servlet 新建项目 写一个类继承HttpServlet&#xff0c;复写doGet(应对Get请求)&#xff0c;doPost(应对…

vue组件传值之$attrs

1.概述&#xff1a;$attrs用于实现当前组件的父组件&#xff0c;向当前组件的子组件通信&#xff08;祖-》孙&#xff09; 2.具体说明&#xff1a;$attrs是一个对象&#xff0c;包含所有父组件传入的标签属性。 注意&#xff1a;$attrs会自动排除props中声明的属性&#xff0…

从0开始深度学习(14)——模型选择、欠拟合、过拟合

① 模型在训练数据上拟合的比在潜在分布中更接近的现象&#xff0c;就叫过拟合&#xff08;overfitting&#xff09; ② 用于对抗过拟合的技术称为正则化&#xff08;regularization&#xff09; 1 训练误差和泛化误差 ①训练误差&#xff08;training error&#xff09;&…

scrapy 爬虫学习之【中医药材】爬虫

本项目纯学习使用。 1 scrapy 代码 爬取逻辑非常简单&#xff0c;根据url来处理翻页&#xff0c;然后获取到详情页面的链接&#xff0c;再去爬取详情页面的内容即可&#xff0c;最终数据落地到excel中。 经测试&#xff0c;总计获取 11299条中医药材数据。 import pandas as…

CTFHUB技能树之HTTP协议——响应包源代码

开启靶场&#xff0c;打开链接&#xff1a; 是个贪吃蛇小游戏&#xff0c;看不出来有什么特别的地方 用burp抓包看看情况&#xff1a; 嗯&#xff1f;点击“开始”没有抓取到报文&#xff0c;先看看网页源代码是什么情况 居然直接给出flag了&#xff0c;不知道这题的意义何在 …

某MDM主数据管理系统与微软Dynamic CRM系统(国内节点)集成案例

一、需求分析 需要完成的核心场景&#xff1a; 客户主数据&#xff1a;通过SAP PO集成中间件平台&#xff0c;某MDM主数据实时推送客户主数据信息至微软CRM系统&#xff0c;方便微软CRM系统进行客户方面的管理&#xff0c;并供微软CRM查询员工信息&#xff0c;修改员工&…

IDEA运行Java程序时出错。提示:命令行过长。通过 JAR 清单或通过类路径文件缩短命令行,然后重新运行。

文章目录 一、遇到问题二、分析问题三、解决办法 一、遇到问题 运行 OpenCVUtils.test 时出错。命令行过长。 通过 JAR 清单或通过类路径文件缩短命令行&#xff0c;然后重新运行。二、分析问题 IDEA提示很明显了。 三、解决办法 运行——>编辑配置 运行/调试配置——&g…

024_Symbolic_Math_in_Matlab符号数学工具箱的使用思路

符号运算与数值计算 缘&#xff0c;妙不可言 给本科、硕士、博士、研究实习员、助理研究员、副研究员改过Matlab代码&#xff0c;最有意思也最好玩的就是兄弟姐妹们喜欢把符号运算跟数值计算混合在一起。 从概念上看&#xff0c;还是挺不错的。 大佬们的计划都是这样的&…

64页精品PPT | 汽车经销商数据应用解决方案

汽车经销商正面临前所未有的盈利能力挑战。从18年起 &#xff0c;传统燃油车汽车行业开始步入低速增长阶段 &#xff0c;卖车已经挣不到钱 &#xff0c;利润往往来自任务完成的厂家返利&#xff1b;新兴的直营模式的出现 &#xff0c;冲击了传统授权经销的方式 &#xff0c;疫情…

车辆管理新篇章:SpringBoot技术解析

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

sns数据分析

探索性数据分析 这一部分目的在于了解数据&#xff0c;包括数据是什么类型&#xff0c;数据有什么特点 数据信息 print(data.shape) data.info()(1086, 12) <class pandas.core.frame.DataFrame> Index: 1086 entries, 2020/7/1 0:00 to nan Data columns (total 12 c…

鸿蒙网络编程系列24-Web组件与应用互操作示例

1. APP内嵌网页与应用互操作概述 在通常的APP开发中&#xff0c;经常会采用内嵌网页的形式&#xff0c;通过网页来展现丰富的动态内容&#xff0c;虽少了很多原生开发的功能&#xff0c;但是这么做无可厚非&#xff0c;毕竟APP需要适配的系统平台很多&#xff0c;比如安卓、苹…

leetcode289:生命游戏

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

babylonjs shader学习之copy shadertoy案例

shadertoy案例&#xff1a; 准备 const onSceneReady (scene: Scene) > {const light new HemisphericLight(light, new Vector3(0, 1, 0), scene);light.intensity 0.7;Effect.ShadersStore[planeMatVertexShader] precision highp float;attribute vec3 position;attr…

SpringMVC一个拦截器和文件上传下载的完整程序代码示例以及IDEA2024部署报错 找不到此 Web 模块的 out\artifacts\..问题

一、SpringMVC一个拦截器和文件上传下载的完整程序代码示例 本文章是一个 SpringMVC拦 截器和文件上传下载的完整程序代码示例&#xff0c;使用的开发工具是 IntelliJ IDEA 2024.1.6 (Ultimate Edition)&#xff0c; 开发环境是 OpenJDK-21 java version 21.0.2。Tomcatt版本为…

Flux.concat 使用说明书

public static <T> Flux<T> concat(Iterable<? extends Publisher<? extends T>> sources)Concatenate all sources provided in an Iterable, forwarding elements emitted by the sources downstream. 连接可迭代集合中提供的所有源&#xff0c;将…