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.pswp.cn/diannao/80879.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/80879.shtml
英文地址,請注明出處:http://en.pswp.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 語言)和強大的硬件集成能力,已成為全球工程師和…