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

目录

[mysql connect](#mysql connect)

介绍

开发环境

编译链接问题

编译

链接

接口介绍

初始化和销毁

mysql_init()

句柄

mysql_close()

链接数据库

mysql_real_connect()

参数

返回值

[show processlist](#show processlist)

给mysql下达命令

mysql_query()

参数

返回值

查询结果的获取

引入

mysql_store_result()

参数

返回值

MYSQL_RES

读取结果集中的元数据

行数/列数

[mysql_fetch_fields() -- 列信息](#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()
cpp 复制代码
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**,其实就是像上面图中画的一样往下遍历
访问列数据

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

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

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

  • 和迭代器类似,每次可以获取一列信息
cpp 复制代码
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

cpp 复制代码
#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就有客户端,没必要我们也弄一个

以及要注意设置编码格式

代码
cpp 复制代码
#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下是可以看到更改的

插入中文也可以:

输出查询结果

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

代码
cpp 复制代码
#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中打印查询结果的样式,只是少了表格结构:

相关推荐
stark张宇23 分钟前
Mysql的安全管理
数据库·后端·mysql
Bro_cat29 分钟前
JavaEE 前后端交互与数据库连接练习
java·服务器·数据库·java-ee·tomcat·交互
熟透的蜗牛35 分钟前
大数据技术(六)—— Hbase集群安装
大数据·数据库·hbase
HappyAcmen2 小时前
关于Redis的面试题目及其答案
数据库·redis·面试
代码欢乐豆2 小时前
NoSQL——期末复习(4)第四章HBase重点思考题
数据库·nosql·hbase
PersistJiao2 小时前
Couchbase是不是MPP数据库
数据库·couchbase
drebander2 小时前
SQL 中复杂 CASE WHEN 嵌套逻辑优化
数据库·sql
撸码到无法自拔3 小时前
72 mysql 的客户端和服务器交互 returnGeneratedKeys
运维·服务器·数据库·mysql
奥顺3 小时前
算命网站源码PHP框架_附2025新版设计书教程
大数据·mysql·开源·php
孙尚香蕉4 小时前
深入剖析MySQL数据库架构:核心组件、存储引擎与优化策略(二)
数据库·oracle