【MySQL】C语言连接MySQL

news2024/11/16 5:56:34

文章目录

  • 一、引入库
    • 下载库文件
    • 验证是否引入成功
  • 二、MySQL C API相关接口
  • 三、总结


一、引入库

mysql的基础,我们之前已经学过,后面我们只关心使用要 使用C语言连接mysql ,需要使用mysql官网提供的库,大家可以去MySQL官网下载。

下载库文件

首先,进入MySQL官网,选择 DOWNLOADS, 然后点击 MySQL Community (GPL) Downloads 。如下:

在这里插入图片描述
在这里插入图片描述

因为我们要使用C语言连接MySQL,所以这里选择 C API (libmysqlclient)。如下:

在这里插入图片描述

最后选择适合自己平台的mysql connect 库,然后点击下载就行了。如下:

在这里插入图片描述

上传到云服务器

在这里插入图片描述

进入解压目录后,可以看到有一个include子目录和一个lib子目录。如下:

在这里插入图片描述


当然我们可以通过yum来直接安装mysql client 以及 mysql devel,因为之前我们在安装mysql-commun-server时已经配置了mysql相关的yum源了。

yum install -y mysql-community-devel
yum install -y mysql-community-server

安装完毕后我们就可以在 /usr/include/mysql 目录下找到mysql相关的头文件了。

在这里插入图片描述

同时,我们也可以在 /lib64/mysql /以及 /usr/lib64/mysql 目录下找到mysql对应的动态库以及静态库了。

在这里插入图片描述


验证是否引入成功

现在,我们就可以通过mysql目录下头文件中提供的相关函数来连接数据库了。

这里我们可以通过mysql_get_client_info()函数来验证一下mysql相关头文件以及动态库是否被成功引入。

#include <iostream>
#include <mysql/mysql.h>
using namespace std;

int main()
{
	cout << "MySQL Client Version:" << mysql_get_client_info() << endl;
	return 0;
}
# -L:指明库文件的所在路径
# -l:指明所要链接的库
test:test.cc
	g++ -o $@ $^  -std=c++11 -L/lib64/mysql -lmysqlclient

.PHONY:clean
clean:
	rm -f test

这里说明一下:

  • -I:用于指明头文件的搜索路径。
  • -L:用于指明库文件的搜索路径。
  • -l:用于指明需要连接库文件路径下的哪一个库。

在这里插入图片描述

这里有几个需要注意的地方:

  • 由于我们要使用的mysql C库中的函数,所以在test.cc中我们需要包含mysql相关的头文件。
  • 在程序编译时,我们需要使用-I 选项来指定我们要链接的mysql动态库,并且动态库的库名称是去掉前缀lib以及后缀.so后的剩余部分。(libmysqlclient.so -> mysqlclient)
  • 由于动态库在 /usr/lib64/mysql/ 目录下,而系统默认库路径是 /usr/lib64/,所以我们还需要使用 -L选项来指定动态库的路径。
  • mysql C语言相关头文件在 /usr/include/mysql/ 目录下,而系统默认的头文件搜索路径是 /usr/include/,所以按道理来说,我们也是需要使用 -I 选项来指明头文件路径的。但这里由于我们在编写源程序,包含头文件时使用的是 mysql/mysql.h,而不仅仅是mysql.h,所以不需要指定。

二、MySQL C API相关接口

初始化MySQL

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

MYSQL *m= mysql_init(nullptr); // 函数返回值:失败返回 NULL

mysql_init 函数的参数以及返回值都是 MYSQL 指针类型,对于 MYSQL,大家把它类比到C语言中的文件指针来理解即可。MYSQL 和C语言文件 FILE 一样,本质上都是一个结构体。

typedef struct st_mysql
{
  NET		net;			/* Communication parameters */
  unsigned char	*connector_fd;		/* ConnectorFd for SSL */
  char		*host,*user,*passwd,*unix_socket,*server_version,*host_info;
  char          *info, *db;
  struct charset_info_st *charset;
  MYSQL_FIELD	*fields;
  MEM_ROOT	field_alloc;
  my_ulonglong affected_rows;
  //...
  char *info_buffer;
  void *extension;
} MYSQL;

在这里插入图片描述

连接MySQL

初始化完毕后,我们需要使用 mysql_real_connect 函数来连接数据库。

MYSQL *
mysql_real_connect(MYSQL *mysql,       // MYSQL结构体指针对象
                   const char *host,   // mysqld服务进程所在的主机
                   const char *user,   // 登录MySQL的用户
                   const char *passwd, // 用户密码
                   const char *db,     // 要访问的数据库
                   unsigned int port,  // mysqld服务进程的端口号
                   const char *unix_socket,    // 默认设为NULL即可
                   unsigned long client_flag)  // 默认设为0即可
// 函数返回值:失败返回0,成功返回传入的MYSQL指针

在这里插入图片描述

设置连接字符集

我们之前在创建数据库时默认使用的字符集是 utf8,而C语言连接数据时默认的字符集是 latin1 的,这就会导致我们在向表中插入中文数据时,由于字符集不匹配,最终数据库中存储的数据显式出来是乱码。

所以,我们需要使用 mysql_set_character_set 函数设置连接字符集为 utf8

int mysql_set_character_set(MYSQL *mysql, const char *csname)
// 函数返回值:返回0表示成功,非0表示失败
int n = mysql_set_character_set(mfp, "utf8");
if(n != 0) { cout << "warning: character set fail" << endl; }

下发mysql指令

在成功连接到数据库之后,我们就可以通过 mysql_query 函数来下发 mysql 指令了。

int mysql_query(MYSQL *mysql, const char *stmt_str)
// 函数返回值:执行成功返回0,失败返回非0
string sql;
while (true)
{
	cout << "mysql>>> ";
	getline(cin, sql);
	int n = mysql_query(mfp, sql.c_str());
	if (n != 0)
	{
		cout << sql << " fail" << endl;
	}
	else
		cout << sql << " success" << endl;
}

在这里插入图片描述

需要注意的是,我们在使用 mysql client 时,一条 sql 语句需要以分号结尾;但是在C语言中,sql 语句可以不用带分号,当然带上也没事。

获取mysql查询结果

我们上面是对数据库执行增删改操作,它们相对来说比较简单,因为我们只需要将指令下发给数据库即可,后面的事情我们不必关心。但如果我们执行的是查询操作,则需要通过 mysql_store_result 函数来获取查询结果。

MYSQL_RES *mysql_store_result(MYSQL *mysql)
// 函数返回值:失败返回 NULL,成功返回一个非空的 MYSQL_RES 类型的结构体指针

实际上,mysql_store_result 函数会调用 MYSQL 结构体变量中的 st_mysql_methods 字段中的 read_rows 函数指针来获取查询的结果;然后将查询结果保存到 MYSQL_RES 结构体中并返回结构体指针。这样,当执行完 mysql_store_result 以后,其实数据都已经在MYSQL_RES 变量中了,我们直接从中获取即可。

需要注意的是,MYSQL_RES 是通过 malloc/new 空间的方式来保存查询结果的,所以当我们使用完毕之后,一定要记得释放 MYSQL_RES 对象,否则就会造成内存泄漏。同时,MYSQL_RES 结构体中存在查询结果的列数、列信息、行数、行内容等属性,我们需要使用对应的函数来获取这些信息。

获取结果列数

unsigned int mysql_num_fields(MYSQL_RES *result)

获取结果中每一列的列属性

MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *res);

关于 MYSQL_FIELD 结构体,它里面包含了列的各种属性信息,包括列名称、列类型、列大小、列属于哪个表哪个库等等。

在这里插入图片描述

同时,我们可以通过重复调用 mysql_fetch_field 函数来获取表中每个列字段的 MYSQL_FIELD 结构,即当我们下次再调用 mysql_fetch_field 函数时,会自动获取到表中下一个列的属性信息,而不需要我们手动指定访问的是哪一列。这和C++中的迭代器很类似。 这种类似迭代器的功能应该是与 MYSQL_RES 中的 current_field 字段有关。

在这里插入图片描述

当然,我们也可以通过调用 mysql_fetch_fields 函数一次获取到所有列的属性信息,然后分别打印。

MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res);

获取结果行数

my_ulonglong mysql_num_rows(MYSQL_RES *result)

获取结果中每一行的具体内容

MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)

MYSQL_ROW 本质上其实是一个二级指针,我们可以把它当作一个一级指针数组来看待,数组中的每个元素都是一级指针。同时,由于 MYSQL_RES 中保存的是查询到的多行结果,所以我们可以将 MYSQL_RES 看作是一个二级指针数组,数组中的每个元素都是二级指针 (MYSQL_ROW)。

在这里插入图片描述

释放 MYSQL_RES 对象

由于 MYSQL_RES 保存查询结果的空间是通过 malloc/new 得到的,所以当我们使用完毕后需要释放掉 MYSQL_RES 对象,防止内存泄露。

void mysql_free_result(MYSQL_RES *result)
mysql_free_result(res);

关闭MySQL连接

当我们使用完 MySQL 后,需要关闭 MySQL 之前建立的连接。

void mysql_close(MYSQL *sock);
mysql_close(mfp);

MySQL其他操作

除了上述这些操作外,MySQL C API 还支持事务、回滚等常见操作,感兴趣的同学可以了解一下。

my_bool STDCALL mysql_autocommit(MYSQL * mysql, my_bool auto_mode);
my_bool STDCALL mysql_commit(MYSQL * mysql);
my_bool STDCALL mysql_rollback(MYSQL * mysql);

三、总结

使用 MySQL C API 连接数据库进行简单操作的步骤如下:

  1. 初始化 MYSQL 结构体指针 – mysql_init。
  2. 连接 MySQL – mysql_real_connect:需要指定数据库服务所在主机、端口以及登录mysql的用户和密码等信息。
  3. 下发 MySQL 指令 – mysql_query。
  4. 获取 MySQL 查询结果:将查询结果转储到 MYSQL_RES 中 – mysql_store_result,获取查询结果的行数 – mysql_num_rows,获取查询结果列数 – mysql_num_fields,获取单个/所有列字段的 MYSQL_FIELD 属性信息 – mysql_fetch_field/mysql_fetch_fields,获取查询结果单行的内容 (不包含属性行) – mysql_fetch_row。
  5. 释放 MYSQL_RES 对象 – mysql_free_result。
  6. 关闭 MySQL 连接 – mysql_close。

整体代码

#include <iostream>
#include <cstring>
#include <mysql/mysql.h>
using namespace std;

const string host = "127.0.0.1";
const string user = "cjl";
const string password = "Cjl1314520@@..";
const string db = "test";
unsigned int port = 3306;

int main()
{
	// 验证C库是否引入成功
	// cout << "mysql version: " << mysql_get_client_info() << endl;

	// 初始化MySQL指针
	MYSQL *mfp = mysql_init(nullptr);
	if (mfp == nullptr)
	{
		cerr << "mysql init error" << endl;
		return 1;
	}
	cout << "mysql init success" << endl;

	// 连接数据库
	if (mysql_real_connect(mfp, host.c_str(), user.c_str(), password.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
	{
		cerr << "mysql connection error: " << endl;
		return 2;
	}
	cout << "mysql connection success!" << endl;

	//设置连接字符集
	int n = mysql_set_character_set(mfp, "utf8");
	if (n != 0)
	{
		cout << "warning: character set fail" << endl;
	}

	// 下发mysql指令--查询
	std:string sql = "select * from students";
    if(mysql_query(mfp, sql.c_str()) != 0)
    {
        cout<<"查询数据失败!"<<endl;
        return 2;
    }
    cout<<"查询数据成功!"<<endl;

    // 获取查询结果 --将查询结果转储到MYSQL_RES中
    MYSQL_RES* res = mysql_store_result(mfp);

	// 获取结果集中的行数和列数
    int rows = mysql_num_rows(res); //数据的行数
    int cols = mysql_num_fields(res); //数据的列数

    // 获取每列的属性并打印列名 -- 一次获取单列
    MYSQL_FIELD* fields = mysql_fetch_fields(res);
    for(int i = 0;i < cols;i++)
    {
        cout<<fields[i].name<<"\t";
    }
	cout<<endl;

	// 一次获取全部列字段的属性信息,然后分别打印
    // MYSQL_FIELD *total_fields = mysql_fetch_fields(res);
    // for(int i = 0; i < colCount; i++)
    // {
    //     cout << total_fields[i].name << '\t';
    // }
    // cout << endl;

    // 打印结果集中的行内容
    for(int i = 0;i < rows;i++)
    {
        //获取一行数据并进行打印
        MYSQL_ROW row = mysql_fetch_row(res);
        for(int j = 0;j < cols;j++)
        {
            cout<<row[j]<<"\t";
        }
        cout<<endl;
    }
    mysql_free_result(res); //释放内存空间
    
    //4、关闭数据库
    mysql_close(mfp);
    cout<<"数据库关闭成功!"<<endl;

	// 简单mysql客户端的 增删改功能
	// string sql;
	// while (true)
	// {
	// 	cout << "mysql>>> ";
	// 	getline(cin, sql);
	// 	int n = mysql_query(mfp, sql.c_str());
	// 	if (n != 0)
	// 	{
	// 		cout << sql << " fail" << endl;
	// 	}
	// 	else
	// 		cout << sql << " success" << endl;
	// }

	return 0;
}

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

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

相关文章

随机漫步【scatter的使用】

去掉scatter的坐标轴&#xff08;未成功版&#xff09; import matplotlib.pyplot as plt from random import choice class RandomWalk():def __init__(self,num_points 5000):self.num_points num_pointsself.x_values [0]self.y_values [0]def fill_walk(self):while l…

父组件中 arr.push改变数组,但是子组件监听不到 arr 的变化

目录 一、问题 二、解决方法 三、总结 tiips:如嫌繁琐&#xff0c;直接移步总结即可&#xff01; 一、问题 1.真是奇怪呀&#xff0c;一般来说通过 push方法改变 数组&#xff0c;是一定会有响应式的&#xff0c;那就可以监听到变化。但是我今天却遇到了一件奇怪的事情。在…

多模态推荐系统综述:四、模型优化

四、模型优化 由于多模态信息的存在&#xff0c;当多模态编码器和推荐模型一起训练时&#xff0c;模型训练的计算要求大大增加。因此&#xff0c;多模态推荐模型在训练过程中可以分为两类&#xff1a;端到端训练和两步训练。 端到端训练可以利用反向传播获得的每个梯度来更新模…

2024.1.11 关于 Jedis 库操作 Redis 基本演示

目录 引言 通用命令 SET & GET EXISTS & DEL KEYS EXPIRE & TTL TYPE String 类型命令 MGET & MSET GETRANGE & SETRANGE APPEND INCR & DECR List 类型命令 LPUSH & LRANG LPOP & LPOP BLPOP & BRPOP LLEN Set 类型命…

Shutter Encoder多媒体转换v17.8

软件介绍 多媒体包含种类繁多的各种文件格式&#xff0c;每种格式都有其不同的特征和所谓的“怪癖”。 因此&#xff0c;如果使用多种图像、视频或音频格式&#xff0c;找到一个集中的软件来从一个地方处理所有这些格式可能会非常棘手。 这就是 Shutter Encoder 基本上允许做的…

科研绘图(二)气泡图

气泡矩阵图&#xff08;Bubble Matrix Plot&#xff09;&#xff0c;通常用于显示三个变量之间的关系。这种图表类型将数据点表示为气泡的形式&#xff0c;其中气泡的大小通常表示第三个数值变量的大小。图表的X轴和Y轴代表两个分类或定量变量。颜色可能代表另一个分类变量或是…

计算机缺失msvcp120.dll的最新解决方法,实测可以完美修复

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp120.dll丢失”。msvcp120.dll是Microsoft Visual C Redistributable Package的一部分&#xff0c;它是运行许多基于Windows操作系统的应用程序所必需的动态链接库文件之一。如果计算机…

矿山无人驾驶方案

矿山无人驾驶运输系统&#xff0c;可实现露天矿采煤装载运输的无人化&#xff0c;满足智能矿山安全、高效、绿色、环保等目标。 无人驾驶应用的总体技术架构包括“车端、场端、云端”三个层面以及相应的安全保障体系&#xff0c;其中车端的智能矿卡具备车辆感知、通信、决策和执…

数字信号处理教程学习笔记1-第2章时域中的离散信号和系统

信号处理的任务示意方框图 模拟信号和数字信号分别是啥样的,有啥区别

【AI视野·今日CV 计算机视觉论文速览 第286期】Tue, 9 Jan 2024

AI视野今日CS.CV 计算机视觉论文速览 Tue, 9 Jan 2024 Totally 121 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computer Vision Papers Dr$^2$Net: Dynamic Reversible Dual-Residual Networks for Memory-Efficient Finetuning Authors Chen Zhao, Shuming Li…

富唯智能新研发的复合机器人,轻松破解汽车底盘零配件生产中的难题

随着汽车工业的快速发展&#xff0c;对于底盘零配件的需求也日益增长。为了满足市场需求&#xff0c;智能物流解决方案在汽车底盘零配件生产中扮演着越来越重要的角色。如何实现高效、准确的生产和物流管理&#xff0c;以满足市场快速变化的需求&#xff0c;成为了汽车生产商亟…

日期类的实现|运算符重载的复用

前言 通过前面C入门与类与对象的学习&#xff0c;今天我们将运用所学的知识点完成一个Date类。 本节目标 运用所学知识完成Date类。详细讲解运算符各种重载。理解运算符重载的复用。 一、Date类的六个默认成员函数 六个成员函数&#xff0c;Date类只需要自己实现构造函数即可…

比尔盖茨:如果只能解决一个问题,我的答案总是营养不良

谷禾健康 当地时间12月19日&#xff0c;微软联合创始人、亿万富翁比尔盖茨发布了对来年的年度预测&#xff0c;称 2024 年将是一个“转折点”。 在这封长达 10 页的信中他展示了对人工智能领域的更多创新、婴儿营养不良问题的突破、气候变化谈判的进展等多方面的期待。 人工智能…

vue-virtual-scroll-list(可单选、多选、搜索查询、创建条目)

element-ui-解决下拉框数据量过多问题&#xff08;vue-virtual-scroll-list&#xff09;_element-ui下拉框数据太多如何优化-CSDN博客 的升级版 参考链接&#xff1a;封装el-select&#xff0c;实现虚拟滚动,可单选、多选、搜索查询、创建条目-CSDN博客 1.封装组件 select.v…

计算机组成原理-计算机的发展(计算机系统 硬件发展 软件发展 微处理器和微计算机的发展 摩尔定律 发展趋势)

文章目录 总览什么是计算机系统软件硬件的发展第一代第二代第三代第四代微处理器的发展相关人物摩尔定律 软件的发展目前的发展趋势小结 总览 什么是计算机系统 软件 语言处理程序就是编译程序之类的 调试代码就是服务程序 硬件的发展 第一代 逻辑元件&#xff1a;处理电信…

通达信波动指数指标公式,识别盘整还是趋势

波动指数(Choppiness Index)是由澳大利亚商品交易员E.W. Dreiss开发的技术指标&#xff0c;用来判断市场是盘整还是趋势。该指标属于非方向性指标&#xff0c;不用于判断市场方向&#xff0c;而仅用于识别市场趋势。 指标的取值范围为0到100&#xff0c;数值越高&#xff0c;表…

Linux进程管理、ps命令、kill命令

每一个程序在运行的时候都会被操作系统注册为系统中的一个进程 补充一下操作系统的内容&#xff1a; 进程实体&#xff08;又称进程映像&#xff09;&#xff1a;程序段、相关数据段、PCB三部分构成 进程是进程实体的运行过程&#xff0c;是系统进行资源分配的一个独立单位 …

xtdrone用键盘控制无人机飞行 无法起飞

运行案例 解锁无人机螺旋桨转动但无法起飞 也未报错 解决方法&#xff1a; 在QGC中修改&#xff1a;PX4飞控EKF配置 将PX4使用的EKF配置为融合GPS的水平位置与气压计高度。 如果我们想使用视觉定位&#xff0c;就需要把修改配置文件。 此修改意味着EKF融合来自mavros/vision_…

【QUARTZ】springboot+quartz动态配置定时任务

Quartz 介绍 Quartz 定时任务可分为Trigger&#xff08;触发器&#xff09;、Job&#xff08;任务&#xff09;和Scheduler&#xff08;调度器&#xff09;&#xff0c;定时任务的逻辑大体为&#xff1a;创建触发器和任务&#xff0c;并将其加入到调度器中&#xff0c;如下图所…

【Android+物联网】Android封装MQTT连接阿里云物联网平台

前言&#xff1a; 亲测可行&#xff0c;本文实现Android封装MQTT连接阿里云物联网平台。将MQTT协议和连接阿里云平台的操作通过Android studio写入APP中&#xff0c;并简单设计UI。实现手机APP远程控制单片机LED灯亮灭的功能。 关于《Android软件开发》&#xff0c;见如下专栏…