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

相关推荐
abandondyy1 小时前
MySQL---主从复制和读写分离
数据库·mysql
DEARM LINER2 小时前
mysql 巧妙的索引
数据库·spring boot·后端·mysql
不惑_3 小时前
Redis与MySQL双写一致性的缓存模式
redis·mysql·缓存
码农幻想梦3 小时前
实验九 视图的使用
前端·数据库·oracle
影子落人间3 小时前
Oracle创建存储过程,创建定时任务
数据库·oracle
大G哥3 小时前
02、Oracle过滤和排序数据
数据库·oracle
代码吐槽菌5 小时前
基于SSM的汽车客运站管理系统【附源码】
java·开发语言·数据库·spring boot·后端·汽车
伏虎山真人5 小时前
开源数据库 - mysql - 组织结构(与oracle的区别)
数据库·mysql·开源
精致先生6 小时前
问题记录01
java·数据库·mybatis
Channing Lewis6 小时前
salesforce developer console 匿名执行是以什么身份执行的
数据库·安全·salesforce