MySQL数据库(14)—— 使用C操作MySQL

目录

一,下载库

二,安装库

三,使用库

3.1 连接数据库

3.2 发送SQL

3.3 获取结果


问题:为什么不使用C++?

解答:使用C的库已经可以完成绝大部分MySQL操作了,并且C++的库的使用更加复杂,C的库使用相对简单,目前我们学习好C的库的部分使用即可(其实是我太菜了不会用C++的库)

一,下载库

下载地址:MySQL :: Download MySQL Connector/C (Archived Versions)

下面是我的环境版本: 

下载后在XShell使用rz命令上传至服务器然后解压即可:

其中include目录下有一堆头文件,lib目录下的则色一堆的动静态库:

二,安装库

我们可以选择把这个include放到lib目录下,也可以直接在代码中指定头文件路径,也可以在编译时指定使用的库,下面我们采用的是第二种方法

当完成上面的步骤后,我们现在要做的就是验证我们的库能否正常使用,我们可以调用mysql_get_client_info函数来获取客户端基本信息:

#include<iostream>
#include "./mysql-connector/include/mysql.h"int main()
{std::cout << mysql_get_client_info() << std::endl;return 0;
}

makefile如下:

test:test.ccg++ -o $@ $^ -std=c++11 -lmysqlclient.PHONY:clean
clean:rm -rf test

如果能正常打印,说明我们的库已经能使用了 

三,使用库

3.1 连接数据库

①初始化数据库

在连接数据库之前,我们需要先创建一个MySQL对象,如下函数声明:

MYSQL *		STDCALL mysql_init(MYSQL *mysql);
  • 对于参数,我们一般传入nullptr,那么这个函数会自动分配一个MySQL对象并返回
  • 如果传入一个地址,那么该函数会在指定的地址完成初始化 

对于 MYSQL 结构体,其内容如下:

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;my_ulonglong insert_id;		/* id if insert on table with NEXTNR */my_ulonglong extra_info;		/* Not used */unsigned long thread_id;		/* Id for connection in server */unsigned long packet_length;unsigned int	port;unsigned long client_flag,server_capabilities;unsigned int	protocol_version;unsigned int	field_count;unsigned int 	server_status;unsigned int  server_language;unsigned int	warning_count;struct st_mysql_options options;enum mysql_status status;my_bool	free_me;		/* If free in mysql_close */my_bool	reconnect;		/* set to 1 if automatic reconnect *//* session-wide random string */char	        scramble[SCRAMBLE_LENGTH+1];my_bool unused1;void *unused2, *unused3, *unused4, *unused5;LIST  *stmts;                     /* list of all statements */const struct st_mysql_methods *methods;void *thd;/*Points to boolean flag in MYSQL_RES  or MYSQL_STMT. We set this flagfrom mysql_stmt_close if close had to cancel result set of this object.*/my_bool *unbuffered_fetch_owner;/* needed for embedded server - no net buffer to store the 'info' */char *info_buffer;void *extension;
} MYSQL;

 ②连接数据库

创建完对象后就可以连接了,连接的接口如下:

MYSQL *		STDCALL 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);
  • mysql: 就是我们前面调用mysql_init函数创建的MySQL对象。
  • host: 需要连接的MySQL服务器的IP地址
  • user: 连接MySQL服务器时,所使用用户的用户名。
  • passwd: 连接MySQL服务器时,所使用用户的密码
  • db: 连接MySQL服务器后,需要使用的数据库。
  • port: 连接的MySQL服务器,所对应的端口号。
  • unix_socket: 连接时应该使用的套接字或命名管道,通常设置为NULL。
  • clientflag: 可以设置为多个标志位的组合,表示允许特定的功能,通常设置为0。
  • 返回值:如果连接成功,返回一个MySQL对象,就是将第一个参数作为输出型参数输出,如果连接hi白就返回null

 ③断开连接

断开连接函数声明:

void STDCALL mysql_close(MYSQL *sock);

 参数就是我们前面的MySQL对象

③连接断开测试 

#include <iostream>
#include <string>
#include "./mysql-connector/include/mysql.h"
using namespace std;const string host = "127.0.0.1";
const string user = "root";
const string passwd = "123456";
const string db = "db"; //要使用的库
const int port = 3306;int main()
{//1、创建MySQL对象MYSQL* ms = mysql_init(nullptr);//2、连接数据库if(mysql_real_connect(ms, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr){cerr<<"MySQL connect error"<<endl;return 1;}cout<<"MySQL connect success" << endl;//3、关闭数据库mysql_close(ms);cout<<"MySQL connect close"<<endl;return 0;
}

3.2 发送SQL

①SQL发送函数

与数据库成功连接之后,就可以向其发送SQL了,发送SQL的函数声明如下:

int		STDCALL mysql_query(MYSQL *mysql, const char *q);
  • 第一个参数就是MySQL对象,第二个参数就是指向需要发送SQL字符串指针
  • 返回0表示SQL执行成功,否则表示执行失败 

②设置编码格式 

客户端和服务器的编码格式可能不一样,会导致双方在进行数据交互时可能会出现乱码,设置编码格式的函数如下:

int          STDCALL mysql_set_character_set(MYSQL *mysql, const char *csname);
  •  第一个参数是MySQL对象,第二个参数就是要设置的编码格式,我们后面都会设置成“utf8”
  • 返回0表示成功,否则失败

③准备测试表 

④插入,删除,修改SQL 

⑤执行结果 

先编译运行 

再次查看数据库,可以发现结果已变化

 

3.3 获取结果

获取结果分为:“获取”、“打印”,

①获取查询结果函数

函数声明如下:

MYSQL_RES *     STDCALL mysql_store_result(MYSQL *mysql);
  • 该函数会调用指定MySQL对象对应的函数指针来获取查询结果,并将结果保存到MYSQL_RES结构体中

MYSQL_RES结构体定义如下:

typedef struct st_mysql_res {my_ulonglong  row_count;MYSQL_FIELD	*fields;MYSQL_DATA	*data;MYSQL_ROWS	*data_cursor;unsigned long *lengths;		/* column lengths of current row */MYSQL		*handle;		/* for unbuffered reads */const struct st_mysql_methods *methods;MYSQL_ROW	row;			/* If unbuffered read */MYSQL_ROW	current_row;		/* buffer to current row */MEM_ROOT	field_alloc;unsigned int	field_count, current_field;my_bool	eof;			/* Used by mysql_fetch_row *//* mysql_stmt_close() had to cancel this result */my_bool       unbuffered_fetch_cancelled;void *extension;
} MYSQL_RES;

 理解MYSQL_RES:

  • mysql的表分为表的属性和表的内容两种,查的结果是被查出来的数据,所以在内存中一定是有一段空间来保存这段数据的,因为mysql将所有的数据读取出来的时候都当作字符串

  • 所以可以把MYSQL_RES *当成char**[]数组,数组里面存的都是另一个char*[]数组的首地址,而这些数组里面的指针分别指向表每一行的各个列数据的地址

②获取查询结果行数和列数 

查询行数函数:

my_ulonglong STDCALL mysql_num_rows(MYSQL_RES *res);

 查询列数函数:

unsigned int STDCALL mysql_num_fields(MYSQL_RES *res);

③获取表属性

前面获取行数和列数输入获取表的内容,而我们现在这个表示获取表的属性

获取表的属性函数如下:

MYSQL_FIELD * STDCALL mysql_fetch_fields(MYSQL_RES *res);

MYSQL_FIELD对象定义如下:

typedef struct st_mysql_field {char *name;                 /* Name of column */char *org_name;             /* Original column name, if an alias */char *table;                /* Table of column if column was a field */char *org_table;            /* Org table name, if table was an alias */char *db;                   /* Database for table */char *catalog;	      /* Catalog for table */char *def;                  /* Default value (set by mysql_list_fields) */unsigned long length;       /* Width of column (create length) */unsigned long max_length;   /* Max width for selected set */unsigned int name_length;unsigned int org_name_length;unsigned int table_length;unsigned int org_table_length;unsigned int db_length;unsigned int catalog_length;unsigned int def_length;unsigned int flags;         /* Div flags */unsigned int decimals;      /* Number of decimals in field */unsigned int charsetnr;     /* Character set */enum enum_field_types type; /* Type of field. See mysql_com.h for types */void *extension;
} MYSQL_FIELD;

④获取查询结果中的一行数据

函数声明如下: 

MYSQL_ROW	STDCALL mysql_fetch_row(MYSQL_RES *result);

MYSQL_ROW本质是一个二级指针,这个二级指针指向一个类似数组的结构,而这个数组里面也是一个一个的指针,这些指针指向的就是这行数据中的多个列信息

⑤查询示例

⑥效果演示

完整代码如下:

#include<iostream>
#include<string>
#include<unistd.h>
#include "./mysql-connector/include/mysql.h"const std::string host = "127.0.0.1";
const std::string user = "root";
const std::string password = "123456";
const std::string db = "db";
const unsigned int port = 3306;int main()
{MYSQL* my = mysql_init(nullptr); //MYSQL就是一个大型结构体,保存了mysql的一些属性,my类似于文件操作的fileif (nullptr == my){std::cout << "init MYSQL error" << std::endl;return 1;  //退出码}if (mysql_real_connect(my, host.c_str(), user.c_str(), password.c_str(), db.c_str(), port, nullptr, 0) == nullptr){std::cout << "connect MySql error" << std::endl;return 2;  //退出码}mysql_set_character_set(my, "utf8");std::string sql = "select * from user;";int n = mysql_query(my, sql.c_str());if (n == 0) std::cout << sql << "success" << std::endl;else{std::cout << sql << "failed" << std::endl;return 3;}MYSQL_RES* res = mysql_store_result(my);  //MYSQL_RES是一个结构体if (nullptr == res){std::cout << "mysql_store_result error" << std::endl;return 4;}int rows = mysql_num_rows(res);  //获取行数int fields = mysql_num_fields(res); //获取列数//打印表属性MYSQL_FIELD* fields_array = mysql_fetch_fields(res); //MYSQL_FIELD也是一个结构体,里面存的是各种属性类型for (int i = 0; i < fields; i++){std::cout << fields_array[i].name << "\t";}std::cout << "\n";//打印内容for (int i = 0; i < rows; i++){MYSQL_ROW row = mysql_fetch_row(res); //这个类似迭代器,会自动向后走for (int j = 0; j < fields; j++){std::cout << row[j] << "\t";}std::cout << "\n";}//打印库名和表名(可以打印很多属性,根据自己需要可以自行打印)std::cout << fields_array[0].db << " " << fields_array[0].table << std::endl;mysql_free_result(res); //释放结果集mysql_init(my);  //已完成对象的创建和初始化,以及清理释放的过程return 0;
}

 

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

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

相关文章

Redis故障防御体系:构建七层免疫系统的设计哲学

当Redis遭遇写入阻塞或服务崩溃时&#xff0c;本质上是系统边界的多重防御机制被击穿。本文摒弃碎片化的解决方案&#xff0c;从系统工程的全局视角&#xff0c;构建七层递进式防御体系&#xff0c;揭示高可用架构的深层设计逻辑。 第一层&#xff1a;动态资源调度 —— 内存的…

在线文本客服系统核心功能解析

在线文本客服系统核心功能解析 在互联网大厂的Java求职者面试中&#xff0c;经常会被问到关于在线文本客服系统的实现和设计。本文通过一个故事场景来展示这些问题的实际解决方案。 第一轮提问 面试官&#xff1a;马架构&#xff0c;欢迎来到我们公司的面试现场。请问您对在…

学成在线。。。

一:讲师管理 介绍:可以实现对讲师的分页展示,多条件组合分页查询,对讲师的添加,修改,删除操作。 针对于添加来说,使用requestBody注解,搭配postmapping接收数据,使用service层的对象,调用mapper方法,向数据库中保存数据。 修改: 先根据讲师id,查询出讲师,再去…

Webug3.0通关笔记17 中级进阶(第01-05关)

目录 第一关 出来点东西吧 1.打开靶场 2.源码分析 3.源码修正 4.文件包含漏洞渗透 第二关 提交方式是怎样的啊&#xff1f; 1.打开靶场 2.源码分析 3.渗透实战 &#xff08;1&#xff09;bp改包法 &#xff08;2&#xff09;POST法渗透 第三关 我还是一个注入 1.打开…

C语言复习笔记--内存函数

在复习完字符函数和字符串函数之后,今天让我们复习一下内存函数吧.这一块的东西不太多,并且与之前的字符串函数有一些地方很相似,所以这里应该会比较轻松. memcpy使用和模拟实现 老规矩,先看函数原型 void * memcpy ( void * destination, const void * source, size_t num );…

【Unity AR开发插件】一、高效热更新:Unity AR 插件结合 HybridCLR 与 ARFoundation 的开源仓库分享

摘要 本篇博客详细介绍了我基于 HybridCLR 与 AR Foundation 的 Unity AR 开发插件&#xff0c;旨在为开发者提供高效的跨平台热更新方案。文章从背景与动机出发&#xff0c;覆盖一键安装工具、环境配置、热更新数据制作与示例程序运行等核心模块&#xff0c;并展示代码结构与使…

数据分析(四):Python Pandas数据输入输出全流程指南

Python Pandas数据输入输出全流程指南 1. 引言 数据输入输出(I/O)是数据分析工作流中最基础也是最重要的环节之一。Pandas提供了丰富的数据读写接口&#xff0c;支持从各种文件格式和数据库中加载数据&#xff0c;以及将处理后的数据保存到不同存储系统中。本文将全面介绍Pan…

人工智能与机器学习:Python从零实现性回归模型

🧠 向所有学习者致敬! “学习不是装满一桶水,而是点燃一把火。” —— 叶芝 我的博客主页: https://lizheng.blog.csdn.net 🌐 欢迎点击加入AI人工智能社区! 🚀 让我们一起努力,共创AI未来! 🚀 前言 在 AI 的热潮中,很容易忽视那些让它得以实现的基础数学和技…

Ubuntu18.04更改时区(图文详解)

Ubuntu18.04更改时区 1、前言2、更改时区3、总结 1、前言 记录一下Ubuntu18.04更改时区的过程&#xff0c;方便自己日后回顾&#xff0c;也可以给有需要的人提供帮助。 2、更改时区 输入下面的指令&#xff0c;进行时区选择 tzselect输入4选择亚洲&#xff0c;输入9选择中…

vue2 项目使用vite2 升级 vite4 后,对别名的解析有问题,导致打包后项目无法正常运行

问题描述&#xff1a; 之前使用的 vite2 版本&#xff0c;需要在 vite.config 里配置 vue 别名&#xff0c;不然会有commonjs 的依赖包找不到 vue&#xff0c;因为 vite 默认使用 esm 版本。 vue: vue/dist/vue.common.prod.js 在 vite2 中可以正常进行打包上线&#xff0c;…

民办生从零学C的第十二天:指针(1)

每日励志&#xff1a;拼搏十年&#xff0c;征战沙场&#xff0c;不忘初心&#xff0c;努力成为一个浑身充满铜臭味的有钱人。 一.内存和地址 1.内存 计算机内存是一系列存储单元的集合&#xff0c;每个存储单元都有唯一的地址来标识。这些存储单元用于存储程序的数据和指令。…

用Postman验证IAM Token的实际操作

当我们需要用Postman发送一个最简单的请求去验证Token的时候我们该怎么办&#xff1f; 【一、步骤】 步骤1&#xff1a;打开Postman&#xff0c;新建一个GET请求 请求地址填&#xff1a; https://iam.cn-north-4.myhuaweicloud.com/v3/auth/projects 解释一下&#xff1a;…

关于常量指针和指向常量的指针

关于指针&#xff0c;对于常量指针和指向常量的指针也是傻傻分不清。看到定义时&#xff0c;不知道是指针不能变&#xff0c;还是指针指向的内容不能变量。 先看形式&#xff1a; const char * A; char * const B; 这两种有什么区别&#xff1f;傻傻分不清。 A这种定义&am…

unity 读取csv

1.读取代码 string filePath Application.streamingAssetsPath "\\data.csv"; public List<MovieData> movieData new List<MovieData>(); private void ReadCSV(string filePath) { List<List<string>> data new List<…

安达发|高效智能塑料切割数控系统 - 全自动化软件解决方案

在当今的制造业中&#xff0c;塑料作为一种轻便、耐用且成本效益高的材料&#xff0c;被广泛应用于各个领域。随着科技的进步和市场需求的变化&#xff0c;塑料加工行业正面临着前所未有的挑战和机遇。为了提高生产效率&#xff0c;降低成本&#xff0c;并满足日益严格的质量标…

c#接口_抽象类_多态学习

c#接口_抽象类_多态学习 学习日志 关于&#xff1a;c#接口_抽象类_多态的学习记录。 一、概念 1. 多态&#xff08;Polymorphism&#xff09; 定义&#xff1a;同一操作作用于不同对象时&#xff0c;表现出不同的行为。实现方式&#xff1a; 继承 方法重写&#xff08;ov…

智能硬件行业售后服务管理:提升客户体验的关键所在

在当今数字化浪潮的推动下&#xff0c;智能硬件行业正以前所未有的速度蓬勃发展。从智能家居设备的普及&#xff0c;到智能穿戴产品的多样化&#xff0c;再到智能办公设备的广泛应用&#xff0c;智能硬件已经深入到我们生活的方方面面。据市场研究机构预测&#xff0c;未来几年…

Vue3 里 CSS 深度作用选择器 :deep()

&#x1f3af; 解释 在 Vue 组件里&#xff0c;CSS 默认是 scoped&#xff08;作用域限定的&#xff09;&#xff0c;只对当前组件生效。 如果你想在 scoped 样式里&#xff0c;穿透到子组件的内部元素&#xff0c;就要用 :deep()。 ✏️ 示例 比如&#xff0c;你有一个子组件…

仙宫云ComfyUI —【Wan2.1】AI视频生成部署

【Wan2.1】AI视频生成本地部署与使用技巧全面详解_哔哩哔哩_bilibili 所有模型下载&#xff1a;https://pan.quark.cn/s/9d793aa1b258 Runninghub本期课程工作流下载&#xff08;可获得1000RH币&#xff09;&#xff1a;https://www.runninghub.cn/?utm_sourcekol01-RH145 仙…

LabVIEW 在测控领域的深度开发与未来发展趋势研究报告 (2025-2030)(原创作品使用请注明出处,三连)

## LabVIEW 在测控领域的深度开发与未来发展趋势研究报告 (2025-2030) ### 引言 LabVIEW(Laboratory Virtual Instrument Engineering Workbench)自 1986 年由美国国家仪器公司(NI)发布以来,凭借其独特的图形化编程语言(G 语言)和强大的硬件集成能力,已成为全球工程师和…