【MySQL】使用C语言连接

news2024/11/16 9:24:16

​🌠 作者:@阿亮joy.
🎆专栏:《零基础入门MySQL》
🎇 座右铭:每个优秀的人都有一段沉默的时光,那段时光是付出了很多努力却得不到结果的日子,我们把它叫做扎根
在这里插入图片描述

目录

    • 👉mysql connect👈
      • 连接库的下载
      • 验证是否引入成功
      • mysql 接口介绍
      • 综合代码
    • 👉总结👈

👉mysql connect👈

连接库的下载

学习 MySQL 的命令行,只是让我们熟悉 MySQL 的命令。在实际工作和项目开发中,我们都是使用封装好的库来连接和访问 MySQL 数据库的。

要使用 C 语言连接 MySQL,需要使用 MySQL官网提供的库,大家可以去官网下载。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
下载完之后,上传到 Linux 服务器上,然后解压就行了。

[root@VM-12-10-centos mysql-connector]# ll
total 68
drwxrwxr-x 2 Joy Joy  4096 Jul 24 13:54 bin
-rw-r--r-- 1 Joy Joy 17987 Jul 13  2017 COPYING
drwxrwxr-x 2 Joy Joy  4096 Jul 24 13:54 docs
drwxrwxr-x 3 Joy Joy  4096 Jul 24 13:54 include
drwxrwxr-x 2 Joy Joy  4096 Jul 24 13:54 lib
-rw-r--r-- 1 Joy Joy 30906 Jul 13  2017 README

[root@VM-12-10-centos mysql-connector]# ll lib/
total 23916
-rw-r--r-- 1 Joy Joy 15948896 Jul 13  2017 libmysqlclient.a
lrwxrwxrwx 1 Joy Joy       20 Jul 13  2017 libmysqlclient.so -> libmysqlclient.so.18
lrwxrwxrwx 1 Joy Joy       23 Jul 13  2017 libmysqlclient.so.18 -> libmysqlclient.so.18.4.
-rwxr-xr-x 1 Joy Joy  8538815 Jul 13  2017 libmysqlclient.so.18.4.

其中 include 目录下包含了所有的方法声明, lib 目录下包含所有的方法实现(打包成库)。然后再将头文件和库文件拷贝到系统目录下就完成安装了。

但是,我们在安装 MySQL 服务时,就已经把 MySQL 的开发包安装好了,也会自动地将头文件和库文件拷贝到系统目录下。

[root@VM-12-10-centos mysql-connector]# rpm -qa | grep mysql
mysql57-community-release-el7-11.noarch
mysql-community-client-5.7.41-1.el7.x86_64
mysql-community-libs-5.7.41-1.el7.x86_64
mysql-community-common-5.7.41-1.el7.x86_64
mysql-community-server-5.7.41-1.el7.x86_64
mysql-community-devel-5.7.43-1.el7.x86_6 ## 开发包

## 如果发现自己没有开发包,可以使用下面的命令进行下载
yum install -y mysql-community-devel

## 查看系统目录下的头文件和库文件
[root@VM-12-10-centos mysql-connector]# ls /usr/include/mysql/
big_endian.h              my_byteorder.h      mysql_com.h         my_sys.h                    sql_state.h
binary_log_types.h        my_command.h        mysql_com_server.h  my_thread.h                 sslopt-case.h
byte_order_generic.h      my_compiler.h       mysqld_ername.h     my_thread_local.h           sslopt-longopts.h
byte_order_generic_x86.h  my_config.h         mysqld_error.h      my_xml.h                    sslopt-vars.h
decimal.h                 my_config_x86_64.h  mysql_embed.h       plugin_audit.h              thr_cond.h
errmsg.h                  my_dbug.h           mysql.h             plugin_ftparser.h           thr_mutex.h
keycache.h                my_dir.h            mysql_time.h        plugin_group_replication.h  thr_rwlock.h
little_endian.h           my_getopt.h         mysql_version.h     plugin.h                    typelib.h
m_ctype.h                 my_global.h         mysqlx_ername.h     plugin_keyring.h
m_string.h                my_list.h           mysqlx_error.h      plugin_validate_password.h
my_alloc.h                mysql               mysqlx_version.h    sql_common.h

[root@VM-12-10-centos mysql-connector]# ls /usr/lib64/mysql/
libmysqlclient.a   libmysqlclient.so.20       libmysqlservices.a  plugin
libmysqlclient.so  libmysqlclient.so.20.3.28  mecab

验证是否引入成功

通过 mysql_get_client_info 函数,来验证我们的引入是否成功。

#include <iostream>
#include <mysql/mysql.h>

using namespace std;

int main()
{
    cout << "MySQL Client Version:" << mysql_get_client_info() << endl;
    return 0;
}

因为我们的连接库所在的路径没有导入到系统的环境变量中,所以我们要通过 -L 选项和 -l 选项来告知编译器库文件所在的路径和所要链接的库。

Makefile

# -L:指明库文件的所在路径
# -l:指明所要链接的库
mysqlClient:mysqlClient.cc
	g++ $@ $^ -o -std=c++11 -L/lib64/mysql -lmysqlclient

.PHONY:clean
clean:
	rm -rf mysqlClient

在这里插入图片描述

mysql 接口介绍

初始化 mysql_init

要使用库,必须先进行初始化。mysql_init 函数会给我们返回一个 MYSQL 句柄,我们后续的操作都需要通过这个 MYSQL 句柄来完成。使用方法如下:

MYSQL *m= mysql_init(nullptr);

连接数据库 mysql_real_connect

初始化完毕之后,必须先连接数据库,才能进行后续操作。(mysql网络部分是基于 TCP/IP 的)。

MYSQL *mysql_real_connect(MYSQL *mysql, const char *host,
						  const char *user,
						  const char *passwd,
						  const char *db,
						  unsigned int port,
						  const char *unix_socket,
						  unsigned long clientflag);
						  
// 建立好链接之后,获取英文没有问题,如果获取中文是乱码:
// 设置链接的默认字符集是utf8,原始默认是latin1
mysql_set_character_set(myfd, "utf8");

第一个参数 MYSQL 是 C API中一个非常重要的变量(mysql_init 的返回值),里面内容非常丰富,有 port、dbname、charset 等连接基本参数。它也包含了一个叫 st_mysql_methods 的结构体变量,该变量里面保存着很多函数指针,这些函数指针将会在数据库连接成功以后的各种数据操作中被调用。mysql_real_connect 函数中各参数,基本都是顾名思意,不进行过多的介绍。

关闭 mysql 连接 mysql_close

void mysql_close(MYSQL *sock);

使用完数据库后,需要关闭 mysql 连接,否则会造成内存泄露。

下发 mysql 命令 mysql_query

int mysql_query(MYSQL *mysql, const char *q);

第一个参数上面已经介绍过,第二个参数为要执行的 sql 语句,如:“select * from table”。调用成功的返回值为 0,否则为 1。

获取执行结果 mysql_store_result

sql 执行完以后,如果是查询语句,我们当然还要读取数据。如果 update、insert 等语句,那么就看下操作成功与否即可。那我们来看看如何获取查询结果,如果 mysql_query 返回成功,那么我们就通过 mysql_store_result 这个函数来读取结果。原型如下:

MYSQL_RES *mysql_store_result(MYSQL *mysql);

该函数会调用 MYSQL 变量中的 st_mysql_methods 中的 read_rows 函数指针来获取查询的结果。同时该函数会返回 MYSQL_RES 这样一个变量,该变量主要用于保存查询的结果。同时该函数 malloc 了一片内存空间来存储查询过来的数据,所以我们一定要记的 free(result),不然是肯定会造成内存泄漏的。 执行完 mysql_store_result 以后,其实数据都已经在 MYSQL_RES 变量中了,下面的 API 基本就是读取 MYSQL_RES 中的数据。

获取结果行数 mysql_num_rows

my_ulonglong mysql_num_rows(MYSQL_RES *res);

获取结果列数 mysql_num_fields

unsigned int mysql_num_fields(MYSQL_RES *res);

获取列名 mysql_fetch_fields

MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res);

如:

int fields = mysql_num_fields(res);
MYSQL_FIELD *field = mysql_fetch_fields(res);
int i = 0;
for (; i < fields; i++)
{
    cout << field[i].name << " ";
}
cout << endl;

获取结果内容 mysql_fetch_row

MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);

它会返回一个 MYSQL_ROW 变量,MYSQL_ROW 其实就是 char **,可以当成一个二维数组来使用。

MYSQL_ROW line;
for (int i = 0; i < rows; i++)
{
    line = mysql_fetch_row(res);
    for (int j = 0; j < fields; j++)
    {
        cout << line[j] << " ";
    }
    cout << endl;
}

另外,mysql C API 还支持事务等常用操作,大家自行了解。

综合代码

获取 select 的结果

#include <iostream>
#include <string>
#include <cstdlib>
#include <mysql/mysql.h>
#include <iomanip>

using namespace std;

string User = "Test";
string Host = "127.0.0.1"; // "localhost"
string Password = "123456";
string Database = "my_db";
unsigned int Port = 8888;

int main()
{
    // 初始化 MYSQL 对象
    MYSQL *m = mysql_init(nullptr);
    if (m == nullptr)
    {
        cerr << "mysql_init error" << endl;
        exit(1);
    }

    // 连接数据库
    if (mysql_real_connect(m, Host.c_str(), User.c_str(), Password.c_str(), Database.c_str(), Port, nullptr, 0) == nullptr)
    {
        cerr << "mysql_real_connect error" << endl;
        exit(2);
    }

    // 将 mysql 连接的字符集设置为 utf8
    // 如果没有设置, 有中文将会出现乱码
    mysql_set_character_set(m, "utf8");

    cout << "mysql_real_connect success" << endl;

    // SQL 可以从网络中来,那样就可以将用户的数据存储起来
    // 增删改的 SQL 语句:执行完就可以了
    // 而查的 SQL 语句:执行完还有读取结果
    string insertSql = "insert into emp values (2, '张三', 8888)";
    string deleteSql = "delete from emp where id=2";
    string updateSql = "update emp set sal=9999 where name='张三'";
    string selectSql = "select * from emp";

    int n = mysql_query(m, selectSql.c_str());
    // 查看执行结果: 0 表示执行成功, 1 表示执行失败
    if (n == 0)
    {
        // 获取结果并对结果进行解析
        MYSQL_RES* res = mysql_store_result(m);
        if(res == nullptr) exit(3);
        int rows = mysql_num_rows(res);
        int fields = mysql_num_fields(res);

        MYSQL_FIELD* fieldName = mysql_fetch_fields(res);
        for(int j = 0; j < fields; ++j)
        {
            // 格式控制
            cout << std::setw(10) << std::left;
            cout << fieldName[j].name;
        }
        cout << endl;

        MYSQL_ROW line;
        for(int i = 0; i < rows; ++i)
        {
            // 按行获取结果内容, 获取完会自动移动到下一行
            line = mysql_fetch_row(res);
            for(int j = 0; j < fields; ++j)
            {
                cout << std::setw(10) << std::left;
                cout << line[j];
            }
            cout << endl;
        }

        // 释放内存
        mysql_free_result(res);
    }

    // 关闭 mysql 连接
    mysql_close(m);

    return 0;
}

简易版 mysql 客户端的实现

#include <iostream>
#include <string>
#include <cstring>
#include <iomanip>
#include <cstdlib>
#include <mysql/mysql.h>

using namespace std;

string User = "Test";
string Host = "127.0.0.1"; // "localhost"
string Password = "123456";
string Database = "my_db";
unsigned int Port = 8888;

int main()
{
    // 初始化 MYSQL 对象
    MYSQL *m = mysql_init(nullptr);
    if (m == nullptr)
    {
        cerr << "mysql_init error" << endl;
        exit(1);
    }

    // 连接数据库
    if (mysql_real_connect(m, Host.c_str(), User.c_str(), Password.c_str(), Database.c_str(), Port, nullptr, 0) == nullptr)
    {
        cerr << "mysql_real_connect error" << endl;
        exit(2);
    }

    // 将 mysql 连接的字符集设置为 utf8
    // 如果没有设置, 有中文将会出现乱码
    mysql_set_character_set(m, "utf8");
    cout << "mysql_real_connect success" << endl << endl;

    char sql[1024];
    while (true)
    {
        cout << "mysql> ";
        fgets(sql, sizeof sql, stdin);
        sql[strlen(sql) - 1] = '\0'; // 去掉 '\n'

        int n = mysql_query(m, sql);
        // 查看执行结果: 0 表示执行成功, 1 表示执行失败
        if (n == 0)
        {
            if (strcasestr(sql, "select"))
            {
                // 获取结果并对结果进行解析
                MYSQL_RES *res = mysql_store_result(m);
                if (res == nullptr)
                    exit(3);
                int rows = mysql_num_rows(res);
                int fields = mysql_num_fields(res);

                MYSQL_FIELD *fieldName = mysql_fetch_fields(res);
                for (int j = 0; j < fields; ++j)
                {
                    // 格式控制
                    cout << std::setw(10) << std::left;
                    cout << fieldName[j].name;
                }
                cout << endl;

                MYSQL_ROW line;
                for (int i = 0; i < rows; ++i)
                {
                    // 按行获取结果内容, 获取完会自动移动到下一行
                    line = mysql_fetch_row(res);
                    for (int j = 0; j < fields; ++j)
                    {
                        cout << std::setw(10) << std::left;
                        cout << line[j];
                    }
                    cout << endl;
                }
                cout << endl;
                // 释放内存
                mysql_free_result(res);
            }
            else
            {
                printf("execute %s success\n\n", sql);
            }
        }
        else
        {
            printf("execute %s fail\n\n", sql);
        }
    }

    // 关闭 mysql 连接
    mysql_close(m);

    return 0;
}

在这里插入图片描述

👉总结👈

本篇博客主要讲解了 mysql 连接库的下载和安装、mysql 接口介绍以及实现了简易版的 mysql 客户端等等。以上就是本篇博客的全部内容,如果大家觉得有收获的话,可以点个三连支持一下!谢谢大家啦!💖💝❣️

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/810607.html

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

相关文章

用CSS和HTML写一个水果库存静态页面

HTML代码&#xff1a; <!DOCTYPE html> <html> <head><link rel"stylesheet" type"text/css" href"styles.css"> </head> <body><header><h1>水果库存</h1></header><table>…

函数指针及其使用

类比 数组的地址 函数的地址 数组指针 函数的指针 函数指针的运用 有趣的代码1

从0到1构建基于自身业务的前端工具库

前言 在实际项目开发中无论 M 端、PC 端&#xff0c;或多或少都有一个 utils 文件目录去管理项目中用到的一些常用的工具方法&#xff0c;比如&#xff1a;时间处理、价格处理、解析url参数、加载脚本等&#xff0c;其中很多是重复、基础、或基于某种业务场景的工具&#xff0…

链表(一) 单链表操作详解

文章目录 一、什么是链表二、链表的分类1、单向或者双向2、带头或不带头3、循环或不循环 三、无头单向不循环链表的实现SList.hSList.c动态申请一个节点单链表打印单链表尾插单链表头插单链表的尾删单链表头删单链表查找在pos位置前插入单链表在pos位置之后插入x删除pos位置单链…

自动驾驶下半场的“入场券”

交流群 | 进“传感器群/滑板底盘群/汽车基础软件群/域控制器群”请扫描文末二维码&#xff0c;添加九章小助手&#xff0c;务必备注交流群名称 真实姓名 公司 职位&#xff08;不备注无法通过好友验证&#xff09; 作者 | 张萌宇 自动驾驶战争的上半场拼的是硬件和算法&…

DTC介绍

DTC 一般由3个字节组成&#xff1a; 字节1&#xff1a;High Byte bit 7-6: 对应DTC属于哪一个系统&#xff0c;P: 00动力系统、C: 01底盘、B: 10车身和U: 11通信系统bit 5-4: 用来区分DTC是标准组织所定义还是制造商自定义 00: ISO/SAE01: 制造商10: ISO/SAE11: ISO/SAE bit 3…

【Rust教程 | 基础系列2 | Cargo工具】Cargo介绍及使用

文章目录 前言一&#xff0c;Cargo介绍1&#xff0c;Cargo安装2&#xff0c;创建Rust项目2&#xff0c;编译项目&#xff1a;3&#xff0c;运行项目&#xff1a;4&#xff0c;测试项目&#xff1a;5&#xff0c;更新项目的依赖&#xff1a;6&#xff0c;生成项目的文档&#xf…

python皮卡丘字符打印代码,用python皮卡丘的代码

大家好&#xff0c;本文将围绕python皮卡丘字符打印代码展开说明&#xff0c;python皮卡丘编程代码教程是一个很多人都想弄明白的事情&#xff0c;想搞清楚python皮卡丘编程代码需要先了解以下几个事情。 1、我用python画皮卡丘&#xff0c;没有错误出现&#xff0c;我也打开才…

内网横向移动—NTLM-Relay重放Responder中继攻击LdapEws

内网横向移动—NTLM-Relay重放&Responder中继攻击&Ldap&Ews 1. 前置了解1.1. MSF与CS切换权限1.1.1. CS会话中切换权限1.1.1.1. 查看进程1.1.1.2. 权限权限 1.1.2. MSF会话中切换权限 2. NTLM中继攻击—Relay重放—SMB上线2.1. 案例测试2.1.1. 同账户密码测试2.1.2…

如何使用CRM系统进行客户关系维护管理?

企业要想持续的发展&#xff0c;就必须管理和维护与客户的关系。但如今客户需求更加复杂和多样化&#xff0c;维护客户关系的难度越来越大。许多企业使用CRM系统来帮助自己管理客户关系。通过本文&#xff0c;让您客户关系维护管理全知道。 1、客户画像 CRM系统可以帮助企业建…

【【萌新的stm32学习-1】】

萌新的stm32学习 冯诺依曼结构 采用了分时复用的结构 优点&#xff1a;总线资源占用少 缺点&#xff1a;执行效率低 哈佛结构 执行效率高 总线资源占用多 RISC 这是精简指令集的意思 arm公司 ARMv9是2021年发布的最新 Cortex-A 最好高性能 Cortex-R 中 Cortex-M 低 何为STM…

VScode的简单使用

一、VScode的安装 Visual Studio Code简称VS Code&#xff0c;是一款跨平台的、免费且开源的现代轻量级代码编辑器&#xff0c;支持几乎主流开发语言的语法高亮、智能代码补全、自定义快捷键、括号匹配和颜色区分、代码片段提示、代码对比等特性&#xff0c;也拥有对git的开箱…

Flutter - 微信朋友圈、十字滑动效果(微博/抖音个人中心效果)

demo 地址: https://github.com/iotjin/jh_flutter_demo 代码不定时更新&#xff0c;请前往github查看最新代码 前言 一般APP都有类似微博/抖音个人中心的效果&#xff0c;支持上下拉刷新&#xff0c;并且顶部有个图片可以下拉放大&#xff0c;图片底部是几个tab&#xff0c;可…

使用Docker部署EMQX

原文链接&#xff1a;http://www.ibearzmblog.com/#/technology/info?id9dd5bf4159d07f6a4e69a6b379ce4244 前言 在物联网中&#xff0c;大多通信协议使用的都是MQTT&#xff0c;而EMQX是基于 Erlang/OTP 平台开发的 MQTT 消息服务器&#xff0c;它的优点很多&#xff0c;我…

C语言第十二课---------操作符的介绍与使用(下)

作者前言 &#x1f382; ✨✨✨✨✨✨&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f367;&#x1f382; &#x1f382; 作者介绍&#xff1a; &#x1f382;&#x1f382; &#x1f382;…

第一章操作系统概述

0.定义 操作系统(Operating System&#xff0c;OS)是指控制和管理整个计算机系统的硬件和软件资源&#xff0c;并合理地组织调度计算机的工作和资源的分配;以提供给用户和其他软件方便的接口和环境;它是计算机系统中最基本的系统软件。 操作系统是系统资源的管理者向上层提供方…

C语言:通讯录(文件操作+动态内存管理) 简易版

目录 前言 一&#xff0c;通讯录菜单 二&#xff0c;通讯录菜单主函数 1.使用枚举&#xff1a; 2.主函数&#xff1a; 三&#xff0c;通讯录功能实现 1.创建通讯录 2.初始化通讯录 3&#xff0c;添加联系人 4&#xff0c;删除联系人 5&#xff0c;搜索联系人 6&…

SpringBoot面试题及答案整理

1、什么是 Spring Boot&#xff1f; 多年来&#xff0c;随着新功能的增加&#xff0c;spring 变得越来越复杂。访问spring官网页面&#xff0c;我们就会看到可以在我们的应用程序中使用的所有 Spring 项目的不同功能。如果必须启动一个新的 Spring 项目&#xff0c;我们必须添…

【MTI 6.S081 Lab】Page tables

【MTI 6.S081 Lab】Page tables Speed up system calls (easy)实验任务Hints哪些其它的系统调用能通过这个共享页面变得更快&#xff0c;请解释。解决方案分配和释放页面初始化结构 实验心得 Print a page table (easy)实验任务Hints根据图3-4从文本中解释vmprint的输出。第0页…

机器学习:自动编码器Auto-encoder

Self-supervised Learning Framework 不用标注数据就能学习的任务&#xff0c;比如Bert之类的。但最早的方法是Auto-encoder。 Outline Auto-encoder encoder输出的向量&#xff0c;被decoder还原的图片&#xff0c;让输出的图片与输入的图片越接近越好。 将原始的高维向量变…