【MySQL】mysql訪問

mysql訪問

  • 1.引入MySQL 客戶端庫
  • 2.C/C++ 進行增刪改
  • 3.查詢的處理細節
  • 4.圖形化界面訪問數據庫
    • 4.1下載MYSQL Workbench
    • 4.2MYSQL Workbench遠程連接數據庫

在這里插入圖片描述

點贊👍👍收藏🌟🌟關注💖💖
你的支持是對我最大的鼓勵,我們一起努力吧!😃😃

1.引入MySQL 客戶端庫

從開始到選擇我們用的都是命令行式的mysql訪問mysqld,向mysqld下達我們的指令,其實在數據庫層面上,連接數據庫的客戶端除了現在命令行式的客戶端,還有圖形化界面、網頁版的,當然也包括語言級別的庫或者包幫我們去訪問數據庫。

下面我們就用C/C++訪問數據庫。關于訪問數據庫我們要做兩個準備工作,一是創建一個遠端或者本地訪問的請求也就是創建一個專門用來進行用C/C++訪問客戶端的賬號。

reate user 'connector'@'localhost' identified by 'xxx';

在這里插入圖片描述

然后創建一個數據庫,賦予這個賬號對數據庫中表的所有權限。

在這里插入圖片描述

二是安裝C/C++要能訪問的庫,這個庫有兩種準備,第一種是從官網下載庫,

下面這個是用不同語言連接MYSQL,官方提供的庫。
在這里插入圖片描述
下載推薦的8.0
在這里插入圖片描述

我們用的是linux,所以選擇linux系統x86 64位

在這里插入圖片描述

下載好,上傳到linux,然后解壓一下,mysql-connector是解壓后重命名的

在這里插入圖片描述

這是解壓后的文件,最重要的就是include 頭文件,還有一個lib64 庫

在這里插入圖片描述

未來頭文件給我們提供連接mysql的方法,庫 提供連接mysql的庫函數

在這里插入圖片描述

我們就可以根據頭文件,直接調用頭文件的的方法,在編譯連接的時候把庫連入進來。如果忘記怎么引入,在Linux哪里基礎IO動靜態庫就有對應的方法!

但是這種方式不推薦了!之間不是下載mysql,用yum源下載嗎。yum源它會給我們找到合適的服務器,客戶端,甚至是開發包。所以我們直接在yum哪里去找進行了。

沒下載過mysql 可以下一下如果你安裝過yum對應msyql源的話,如果不會下請移步于
【MySQL】MySQL在 Linux下環境安裝

yum install -y mysql-community-server  

如果你下載過,你就可以看到這里有對應的頭文件,未來我們主要用的就是mysql.h

在這里插入圖片描述

如果你下載過但是找不到頭文件,執行下面的命令,就可以看到了

install -y mysql-devel

mysql庫在系統默認安裝路徑下

在這里插入圖片描述

開發環境我們有已經準備好了,接下來我們學習具體的接口。不過我們通過 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;
}

如果直接編譯肯定會報錯,說的是未定義的引用,也就是這個mysql_get_client_info()找不到。
在這里插入圖片描述

之前基礎IO就說過,你要保證這個外來庫能被正確連接,gcc/g++默認會選擇C和C++的庫,雖然你的mysql在系統中,系統也會默認會去/lib64路徑下去找,

在這里插入圖片描述

但是現在的問題是我怎么知道我需要連接那個庫,盡管能找到這個庫,但是我怎么知道我們該連那個庫呢?所以我們需要需要在編譯的時候就指明需要連那個庫,

g++ -o mytest test.cc -L/lib64/mysql -lmysqlclient

然后就可以打出來所有mysql客戶端的版本,說明這個庫就被重新引入了

在這里插入圖片描述

以前引入外來庫不是還帶上面-I選項,今天這里咋沒有帶。這是因為g++默認會去include里去找。然后拿著代碼里的

在這里插入圖片描述

去找,所有不會報頭文件找不到的問題。如果你非得帶-I,就把前面去掉

在這里插入圖片描述

g++ -o mytest test.cc -I/usr/include/mysql -L/lib64/mysql -lmysqlclient

接下來我們我們通過這個庫它內部給我提供對應的方法來讓我們連接mysqld服務端,然后進行訪問。

2.C/C++ 進行增刪改

接下來我們先認識mysql常用接口。msyql接口介紹

在這里插入圖片描述

這里還有mysql庫為了方便操作mysql,然后提前在庫中給我創建很多的數據結構

在這里插入圖片描述

msyql的是一套網絡服務,就注定了實際在進行mysql操作之前比如下達sql,一定在之前要連接mysql,而在連接mysql之前,我們還要先來創建一下mysql基礎數據結構。要使用庫,必須先進行初始化。mysql_init()幫我們創建一個MYSQL對象

MYSQL *mysql_init(MYSQL *mysql);

成功返回MYSQL對象,失敗返回nullptr,用的時候必須要調用mysql_close()對應的鏈接。

在這里插入圖片描述

MYSQL是 C api中一個非常重要的變量(mysql_init的返回值),里面內存非常豐富,有port,dbname,charset等連接基本參數。它也包含了一個叫 st_mysql_methods的結構體變量,該變量里面保存著很多函數指針,這些函數指針將會在數據庫連接成功以后的各種數據操作中被調用。

MYSQL實際上就是一個結構體里面包含連接mysql相關保存好的一些屬性。這相當于FILE*,用來標識mysql客戶端一些資源,我們把這些東西可以稱之為句柄。

#include <iostream>
#include <mysql/mysql.h>using namespace std;int main()
{// 1. 初始化mysql,構建mysql對象,得到mysql訪問句柄MYSQL* my=mysql_init(nullptr);if (my == nullptr){cerr << "init MySQL error" << endl;return 1;}// 3.用完之后close,釋放資源mysql_close(my);return 0;
}

把數據庫對應的MYSQL結構體對象創建初始化好,最終不用它了把它釋放。可是要訪問mysql之前要先連接數據庫,連接數據庫的函數。

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);

第一個參數就是剛才創建的MYSQL對象。連接成功后把連接成功套接字信息保存到MYSQL對象中。然后要連接的mysql的主機在哪里,用戶是誰,密碼是多少,連接那個數據庫,數據庫的端口號是多少,剩下設置為nullptr,0就可以了。

成功時把我們傳入的MYSQL給我們返回,失敗返回nullptr。

在這里插入圖片描述
最開始創建的只允許在本地主機連接數據庫的用戶就用上了。

#include <iostream>
#include <mysql/mysql.h>
#include <string>using namespace std;const string host="localhost"; //host="127.0.0.1" 也是可以的
const string user="connector";
const string passwd="xxx";
const string db="conn";
unsigned int port=xxx; //自己的端口號不要暴露int main()
{// 1. 初始化mysql,構建mysql對象,得到mysql訪問句柄MYSQL* my=mysql_init(nullptr);if (my == nullptr){cerr << "init MySQL error" << endl;return 1;}// 2.連接數據庫if(mysql_real_connect(my,host.c_str(),user.c_str(),passwd.c_str(),db.c_str(),port,nullptr,0) == nullptr){cerr << "connect MySQL error" << endl;return 2;}cout<<"connect success"<<endl;// 3.用完之后close,釋放資源mysql_close(my);return 0;
}

自此我們完成了連接mysql的第工作

  1. 初始化mysql,構建mysql對象,得到mysql訪問句柄
  2. 進行mysql 的connect連接
  3. 用完mysql之后close

然后就可以對mysql下達sql指令了。這個下達sql指令的函數是mysql_query對數據庫下達指令。第一個參數就是剛才的MYSQL對象,第二個參數就是下達的sql指令。以前我們在命令行寫單sql后面會帶;,但是在這里并不需要帶;or \g,成功時返回0,失敗時返回非0。

在這里插入圖片描述

在此之前可以自己先創建一個表

create table user(id bigint primary key auto_increment,name varchar(32) not null,age int not null,telphone varchar(32) unique);

之前我們學過一個sql指令,查看正在連接數據庫的用戶

show processlist;

可以看到我們C/C++庫確實連接到數據庫了

在這里插入圖片描述

int main()
{// 1. 初始化mysql,構建mysql對象,得到mysql訪問句柄MYSQL *my = mysql_init(nullptr);if (my == nullptr){cerr << "init MySQL error" << endl;return 1;}// 2.連接數據庫if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr){cerr << "connect MySQL error" << endl;return 2;}// cout<<"connect success"<<endl;string sql;while (true){cout << " mysql> ";if (!getline(cin, sql) || sql == "quit"){cout << "Bye" << endl;break;}int n = mysql_query(my, sql.c_str());if (n == 0){cout << sql << " success" << endl;}else{cerr << sql << " error" << endl;return 3;}}// 3.用完之后close,釋放資源mysql_close(my);return 0;
}

這里名字我們先輸入英文,具體原因等會說。下達的這個sql執行可帶;或者不帶;。然后看到我們確實把信息插入到數據庫了。我們其實也可以自己搞一個mysql的客戶端。但是實際上我們也不會這樣做,別人自己有客戶端。我們直接向數據庫下達sql指令就行了。

在這里插入圖片描述

更新

int main()
{// 1. 初始化mysql,構建mysql對象,得到mysql訪問句柄MYSQL *my = mysql_init(nullptr);if (my == nullptr){cerr << "init MySQL error" << endl;return 1;}// 2.連接數據庫if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr){cerr << "connect MySQL error" << endl;return 2;}string sql="update user set name='jim' where id=2";int n=mysql_query(my,sql.c_str());if(n == 0) cout<<sql<<" success"<<endl;else cout<<sql<<" error"<<endl;// 3.用完之后close,釋放資源mysql_close(my);return 0;
}

執行一下,看到id=2的名字確實更新為jim了。

在這里插入圖片描述

所以未來我們所寫的任何的關于數據庫方面的程序,你想使用數據庫,你可以提前建好數據庫賬號然后賦權,并且建表。然后編寫對應C/C++代碼。然后就可以為你的上層進行數據層面上的支撐了。

插入

int main()
{// 1. 初始化mysql,構建mysql對象,得到mysql訪問句柄MYSQL *my = mysql_init(nullptr);if (my == nullptr){cerr << "init MySQL error" << endl;return 1;}// 2.連接數據庫if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr){cerr << "connect MySQL error" << endl;return 2;}//string sql="update user set name='jim' where id=2";string sql="insert into user (name,age,telphone) values ('peter',19,19187654321)";int n=mysql_query(my,sql.c_str());if(n == 0) cout<<sql<<" success"<<endl;else cout<<sql<<" error"<<endl;// 3.用完之后close,釋放資源mysql_close(my);return 0;
}

在這里插入圖片描述

刪除

int main()
{// 1. 初始化mysql,構建mysql對象,得到mysql訪問句柄MYSQL *my = mysql_init(nullptr);if (my == nullptr){cerr << "init MySQL error" << endl;return 1;}// 2.連接數據庫if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr){cerr << "connect MySQL error" << endl;return 2;}//string sql="update user set name='jim' where id=2";//string sql="insert into user (name,age,telphone) values ('peter',19,19187654321)";string sql="delete from user where id=1";int n=mysql_query(my,sql.c_str());if(n == 0) cout<<sql<<" success"<<endl;else cout<<sql<<" error"<<endl;// 3.用完之后close,釋放資源mysql_close(my);return 0;
}

在這里插入圖片描述

單sql本身就是事務,mysql默認事務提交是自動的,所以今天你可以用一個連接訪問數據庫,也可以創建十個連接訪問數據庫,你可以用命令行方式訪問數據庫,也可以用C/C++訪問數據庫。所以數據庫可以存在多個訪問,因為有事務,事務有ACID能保證原子性等等。所以我們在應用層就不用擔心業務代碼執行時出現問題。

mysql_query這個函數現在可以增刪改,那查行不行呢?

int main()
{// 1. 初始化mysql,構建mysql對象,得到mysql訪問句柄MYSQL *my = mysql_init(nullptr);if (my == nullptr){cerr << "init MySQL error" << endl;return 1;}// 2.連接數據庫if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr){cerr << "connect MySQL error" << endl;return 2;}//string sql="update user set name='jim' where id=2";//string sql="insert into user (name,age,telphone) values ('peter',19,19187654321)";//string sql="delete from user where id=1";string sql="select * from user";int n=mysql_query(my,sql.c_str());if(n == 0) cout<<sql<<" success"<<endl;else cout<<sql<<" error"<<endl;// 3.用完之后close,釋放資源mysql_close(my);return 0;
}

別人告訴我成功了啊,然后呢?

在這里插入圖片描述

在我們數據庫語句中,增刪改是最簡單的,因為增刪改只需要保證成功即可,那么增刪改操作一定能完成。而select是最不好處理的,因為當成功執行select語句,只是執行完sql第一步,那select后的數據在那呢?你是不是要把數據給顯示處理或者說讓用戶獲取到,所以還需要在做后面的工作。所以select還有后序獲取數據包括把數據在交給它的調用層。而不像增刪改執行完就完了。

還有一個問題,剛剛在插入的時候,name插入都是英文,那我們插入中文會怎么樣呢?

int main()
{// 1. 初始化mysql,構建mysql對象,得到mysql訪問句柄MYSQL *my = mysql_init(nullptr);if (my == nullptr){cerr << "init MySQL error" << endl;return 1;}// 2.連接數據庫if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr){cerr << "connect MySQL error" << endl;return 2;}//string sql="update user set name='jim' where id=2";//string sql="insert into user (name,age,telphone) values ('peter',19,19187654321)";string sql="insert into user (name,age,telphone) values ('張三',18,11187654321)";//string sql="delete from user where id=1";//string sql="select * from user";int n=mysql_query(my,sql.c_str());if(n == 0) cout<<sql<<" success"<<endl;else cout<<sql<<" error"<<endl;// 3.用完之后close,釋放資源mysql_close(my);return 0;
}

我們插入中文時亂碼了

在這里插入圖片描述

亂碼問題怎么解決?我們的數據庫編碼格式都配過是utf8的。出現亂碼問題,一定是因為客戶端和服務端對編碼問題沒有形成一致。比如說服務端用的是utf8,客戶端用的是latin1。因為我們數據庫編碼都是utf8的,所以一定是客戶端出現了問題。

建立好鏈接之后,獲取英文沒有問題,如果獲取中文是亂碼:設置鏈接的默認字符集是utf8,原始默認是latin1

int main()
{// 1. 初始化mysql,構建mysql對象,得到mysql訪問句柄MYSQL *my = mysql_init(nullptr);if (my == nullptr){cerr << "init MySQL error" << endl;return 1;}// 2.連接數據庫if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr){cerr << "connect MySQL error" << endl;return 2;}// 設置編碼格式mysql_set_character_set(my, "utf8");//string sql="update user set name='jim' where id=2";//string sql="insert into user (name,age,telphone) values ('peter',19,19187654321)";string sql="insert into user (name,age,telphone) values ('李四',18,12187654321)";//string sql="delete from user where id=1";//string sql="select * from user";int n=mysql_query(my,sql.c_str());if(n == 0) cout<<sql<<" success"<<endl;else cout<<sql<<" error"<<endl;// 3.用完之后close,釋放資源mysql_close(my);return 0;
}

設置好編碼,在插入中文就沒問題了。

在這里插入圖片描述

自此我們就已經能夠進行mysql對象初始化,mysql的連接,mysql的關閉,以及通過mysql_query向數據庫下達對應的指令了。下面我們就解決拿到select的數據問題。

3.查詢的處理細節

查sql本身能夠被正確執行,但是執行之后怎么把查的數據交給上層返回給客戶或者把它的數據顯示處理呢?那在執行select的時候要把select的結果通過mysql_query查完之后把結果應該讓我們怎么獲取到呢?實際上mysql_query在執行select的時候會把結果保存到MYSQL這個句柄中。這個句柄是一個結構體它本身里面會包含對應的保存數據的緩存區區域。但是這部分數據依舊要被我們提取出來的。我們通過mysql_store_result這個函數來將結果進行轉儲。這個函數提取并且轉儲到結果集中。會把結果按照條目放置好。

在這里插入圖片描述

是從MYSQL這個句柄中把結果轉儲到MYSQL_RES這個結構中。

在這里插入圖片描述

把查詢結果按照行為單位,全部都放進結果集中。

在這里插入圖片描述

成功返回MYSQL_RES對象,失敗返回nullptr。也可以采用mysql_errno和mysql_error來進行判斷出錯原因。

在這里插入圖片描述

下面我們看看怎么用這個函數

首先先將結果轉儲到MYSQL_RES結構體中。

int main()
{// 1. 初始化mysql,構建mysql對象,得到mysql訪問句柄MYSQL *my = mysql_init(nullptr);if (my == nullptr){cerr << "init MySQL error" << endl;return 1;}// 2.連接數據庫if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr){cerr << "connect MySQL error" << endl;return 2;}// cout<<"connect success"<<endl;// 設置編碼格式mysql_set_character_set(my, "utf8");string sql="select * from user";int n=mysql_query(my,sql.c_str());if(n == 0) {cout<<sql<<" success"<<endl;}else{cout<<sql<<" error"<<endl;return 3;} //轉儲MYSQL_RES* res=mysql_store_result(my);if(res == nullptr){cerr<<"mysql_store_result error"<<endl;return 4;}// 3.用完之后close,釋放資源mysql_close(my);return 0;
}

那MYSQL_RES這個結構體應該如何理解呢?

首先我們要知道我們查出來的是一種表結構,表結構中行列關系是我們打印出來的,尤其是這些分割符,這些東西我們自己打印出來的,并不是在mysql在表中真實存在的。
在這里插入圖片描述

在mysql表中其實存在兩類信息,一類是存儲表結構中的列屬性或者列名稱,還有一類是存儲表中的內容。

在這里插入圖片描述
我們先看內容,這些內容以一定格式先放到MYSQL結構體對象內部,然后在轉儲到MYSQL_RES結構中。轉儲是為了更好的便于做二次處理。

在表中查出來的數據,就一定是在MYSQL內部在內存中保存這部分內容的。mysql將所有數據,讀取出來的時候,全部都當作字符串。 雖然以前它們什么int,char等,但是一旦把數據讀到自定義緩存區中的時候,那么它一定是把所有數據都當作字符串來看待。以前約束類型只是在插入的時候要處理,讀取出來當當作字符串處理。

然后MYSQL_RES要把結果歸置一下,我可以把MYSQL_RES想象成一個存著char**的指針數組。數組大小代表篩選出來的數據記錄有多少行。一條記錄里面有多列,每一列都是字符串。

在這里插入圖片描述

然后這個數組中每一個char** 指針都指向一個存訪char類型的指針數組,指向的是這個數組中首個元素的地址。char** 的指針數組大小代表的是數據記錄有多少行,而每一行char 的指針數組里的char* 依次指向一條記錄的每一列。

在這里插入圖片描述

所以未來想提取一整行,想提取一整行中的列,我可以按照行列去提取!

我們可以把MYSQL_RES當作一個char**xx[]數組去理解,或者當作一個char*[][]數組去理解都可以,怎么方便怎么來。縱向去遍歷每一行,橫向去遍歷一行中每一列。就可以找所有查詢結果都找到。

在這里插入圖片描述

未來MYSQL_RES就以這樣的方式把查詢的結果保存起來。

那結果最終怎么遍歷呢?首先我們要知道這個轉儲的結果有多少行,有多少列!然后按照行列去遍歷。

獲取結果行數mysql_num_rows
參數是MYSQL_RES,從MYSQL_RES結果集中拿結果有多少行。

my_ulonglong mysql_num_rows(MYSQL_RES *res);

獲取結果列數mysql_num_fields

unsigned int mysql_num_fields(MYSQL_RES *res);
int main()
{// 1. 初始化mysql,構建mysql對象,得到mysql訪問句柄MYSQL *my = mysql_init(nullptr);if (my == nullptr){cerr << "init MySQL error" << endl;return 1;}// 2.連接數據庫if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr){cerr << "connect MySQL error" << endl;return 2;}// cout<<"connect success"<<endl;// 設置編碼格式mysql_set_character_set(my, "utf8");string sql="select * from user";int n=mysql_query(my,sql.c_str());if(n == 0) {cout<<sql<<" success"<<endl;}else{cout<<sql<<" error"<<endl;return 3;} MYSQL_RES* res=mysql_store_result(my);if(res == nullptr){cerr<<"mysql_store_result error"<<endl;return 4;}my_ulonglong row=mysql_num_rows(res);my_ulonglong col=mysql_num_fields(res);cout << "行: " << rows << endl;cout << "列: " << cols << endl;// 3.用完之后close,釋放資源mysql_close(my);return 0;
}

目前這個表不就是3行4列嗎

在這里插入圖片描述

那結果怎么拿?遍歷每一行每一列。一行一列的把結果都拿到。
mysql為了很好的支持遍歷,它內部還提供一種數據結構叫做MYSQL_ROW,每次拿到一行。

獲取結果內容mysql_fetch_row

MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);

這個函數就向以前學過的迭代器,當我們第一次調用mysql_fetch_row它內部會為我們維護當前遍歷的第一行,把第一行的結果集以MYSQL_ROW形式返回。當遍歷第二行的時候,只需要在調用一次mysql_fetch_row,不用自己維護行下標,它會自動指向下一行。就如迭代器一樣,只需要按照特定的次數進行遍歷調用就會依次把元素遍歷一遍,特別像迭代器。

可以看到MYSQL_ROW其實就是一個char指針,因為只有char才能指向第一行第二行等等。
在這里插入圖片描述

int main()
{// 1. 初始化mysql,構建mysql對象,得到mysql訪問句柄MYSQL *my = mysql_init(nullptr);if (my == nullptr){cerr << "init MySQL error" << endl;return 1;}// 2.連接數據庫if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr){cerr << "connect MySQL error" << endl;return 2;}// cout<<"connect success"<<endl;// 設置編碼格式mysql_set_character_set(my, "utf8");string sql = "select * from user";int n = mysql_query(my, sql.c_str());if (n == 0){cout << sql << " success" << endl;}else{cout << sql << " error" << endl;return 3;}MYSQL_RES *res = mysql_store_result(my);if (res == nullptr){cerr << "mysql_store_result error" << endl;return 4;}//下面都是和結果集有關的, MYSQL_RESmy_ulonglong rows = mysql_num_rows(res);my_ulonglong cols = mysql_num_fields(res);cout << "行: " << rows << endl;cout << "列: " << cols << endl;//拿結果  for(int i=0;i<rows;++i){MYSQL_ROW line=mysql_fetch_row(res);for(int j=0;j<cols;++j){cout<<line[j]<<"\t"; }cout<<endl;}// 3.用完之后close,釋放資源mysql_close(my);return 0;
}

現在我們就可以把select的結果都拿到了!

在這里插入圖片描述

剛才說了在獲取msyql表內容的時候,我們除了獲取表格中內容,它的列屬性我們也想獲取。想知道它是那一列的,或者想知道當前查的是那張表,那個數據庫。怎么辦呢?我們有另一個接口。

獲取列名mysql_fetch_fields

MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res);

與mysql_fetch_fields相對的還有一個mysql_fetch_field接口,mysql_fetch_fields以數組形式返回的是所有的列屬性對應的結構體。每一列屬性都是一個結構體。
mysql_fetch_field可以讓你依次遍歷所有列,以列為單位,第一次是第一列,第二次是第二列,也就像迭代器。

在這里插入圖片描述

這里我們就不麻煩了,直接一次獲得所有列屬性。然后可以遍歷所有列把列名稱打印出來。

int main()
{// 1. 初始化mysql,構建mysql對象,得到mysql訪問句柄MYSQL *my = mysql_init(nullptr);if (my == nullptr){cerr << "init MySQL error" << endl;return 1;}// 2.連接數據庫if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr){cerr << "connect MySQL error" << endl;return 2;}// cout<<"connect success"<<endl;// 設置編碼格式mysql_set_character_set(my, "utf8");string sql = "select * from user";int n = mysql_query(my, sql.c_str());if (n == 0){cout << sql << " success" << endl;}else{cout << sql << " error" << endl;return 3;}MYSQL_RES *res = mysql_store_result(my);if (res == nullptr){cerr << "mysql_store_result error" << endl;return 4;}//下面都是和結果集有關的, MYSQL_RESmy_ulonglong rows = mysql_num_rows(res);my_ulonglong cols = mysql_num_fields(res);cout << "行: " << rows << endl;cout << "列: " << cols << endl;//屬性MYSQL_FIELD* fields=mysql_fetch_fields(res);for(int i=0;i<cols;++i){cout<<fields[i].name<<"\t";}cout<<endl;//內容for(int i=0;i<rows;++i){MYSQL_ROW line=mysql_fetch_row(res);for(int j=0;j<cols;++j){cout<<line[j]<<"\t"; }cout<<endl;}// 3.用完之后close,釋放資源mysql_close(my);return 0;
}

自此列名稱我們就拿到了。

在這里插入圖片描述
如果你將來想獲取什么屬性就直接去獲取。

int main()
{// 1. 初始化mysql,構建mysql對象,得到mysql訪問句柄MYSQL *my = mysql_init(nullptr);if (my == nullptr){cerr << "init MySQL error" << endl;return 1;}// 2.連接數據庫if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr){cerr << "connect MySQL error" << endl;return 2;}// cout<<"connect success"<<endl;// 設置編碼格式mysql_set_character_set(my, "utf8");string sql = "select * from user";int n = mysql_query(my, sql.c_str());if (n == 0){cout << sql << " success" << endl;}else{cout << sql << " error" << endl;return 3;}MYSQL_RES *res = mysql_store_result(my);if (res == nullptr){cerr << "mysql_store_result error" << endl;return 4;}//下面都是和結果集有關的, MYSQL_RESmy_ulonglong rows = mysql_num_rows(res);my_ulonglong cols = mysql_num_fields(res);cout << "行: " << rows << endl;cout << "列: " << cols << endl;//屬性MYSQL_FIELD* fields=mysql_fetch_fields(res);for(int i=0;i<cols;++i){cout<<fields[i].name<<"\t";}cout<<endl;//內容for(int i=0;i<rows;++i){MYSQL_ROW line=mysql_fetch_row(res);for(int j=0;j<cols;++j){cout<<line[j]<<"\t"; }cout<<endl;}cout<<fields[0].db<<" "<<fields[0].table<<endl;// 3.用完之后close,釋放資源mysql_close(my);return 0;
}

在這里插入圖片描述

最終我們就把mysql的查詢結果獲取到,然后轉儲到結果集,然后從結果集中提取行列,還有其他屬性和內容。現在我們對增刪查改就有一個完整的認識了。

但是還有一個細節mysql_store_result會把查詢結果由MYSQL轉儲到MYSQL_RES里,MYSQL_RES一定要為我們malloc一大堆空間,所以我們一定要記的 free(result),不然是肯定會造成內存泄漏的。我們不能直接用C的free或者C++的delete,而用的是mysql庫提供的這個函數,把結果集中空間釋放掉。

在這里插入圖片描述
在這里插入圖片描述

int main()
{// 1. 初始化mysql,構建mysql對象,得到mysql訪問句柄MYSQL *my = mysql_init(nullptr);if (my == nullptr){cerr << "init MySQL error" << endl;return 1;}// 2.連接數據庫if (mysql_real_connect(my, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr){cerr << "connect MySQL error" << endl;return 2;}// cout<<"connect success"<<endl;// 設置編碼格式mysql_set_character_set(my, "utf8");string sql = "select * from user";int n = mysql_query(my, sql.c_str());if (n == 0){cout << sql << " success" << endl;}else{cout << sql << " error" << endl;return 3;}MYSQL_RES *res = mysql_store_result(my);if (res == nullptr){cerr << "mysql_store_result error" << endl;return 4;}//下面都是和結果集有關的, MYSQL_RESmy_ulonglong rows = mysql_num_rows(res);my_ulonglong cols = mysql_num_fields(res);cout << "行: " << rows << endl;cout << "列: " << cols << endl;//屬性MYSQL_FIELD* fields=mysql_fetch_fields(res);for(int i=0;i<cols;++i){cout<<fields[i].name<<"\t";}cout<<endl;//內容for(int i=0;i<rows;++i){MYSQL_ROW line=mysql_fetch_row(res);for(int j=0;j<cols;++j){cout<<line[j]<<"\t"; }cout<<endl;}cout<<fields[0].db<<" "<<fields[0].table<<endl;//釋放結果集mysql_free_result(res);// 3.用完之后close,釋放資源mysql_close(my);return 0;
}

可以看到對于讀取的處理其實是挺麻煩的。

我們常用的接口就這些,對于一般數據庫讀取沒有任何問題。

最后,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命令行式的、剛剛就是mysql的C/C++的連接方案,我們還可以通過圖形化界面連接數據庫。

4.圖形化界面訪問數據庫

這里推薦幾個好用的圖形化界面。

Nacicat是一個桌面版的mysql數據庫管理和開發工具,以圖形化界面顯示數據庫的操作。雖然這個工具非常好用,但遺憾的是,這個軟件是收費的。可以自己在網上找找它的破解版。

在這里插入圖片描述
SQLyog 也是一個易于使用的、快速而簡潔的圖形化管理MYSQL數據庫的工具,它能夠在任何地點有效地管理你的數據庫。但同樣的,雖然它用起來很舒服,但它也是收費的
在這里插入圖片描述
MYSQL Workbench是mysql官方提供的數據庫管理和開發工具,支持圖形化界面。雖然它在使用上并沒有上面的Navicat和SQLyog好用,但優點就是它是免費的。這里我們重點就用它。

4.1下載MYSQL Workbench

我們可以直接去mysql官網上去找到它,然后下載。

在這里插入圖片描述

往下翻找到這個然后進去

在這里插入圖片描述

找到MySQL Workbench然后進去

在這里插入圖片描述

選擇對應的操作系統,直接下載就行了

在這里插入圖片描述

下好之后運行就是這個樣子

在這里插入圖片描述

4.2MYSQL Workbench遠程連接數據庫

MYSQL Workbench也是一個客戶端,說白了它和我們自己寫的C/C++客戶端和曾經mysql對應的命令行客戶端是沒有任何差別的,它也要進行網絡請求,也要進行登錄。所以mysql一定要允許這個用戶進行遠程登錄。

因此我們在創建一個允許遠程登錄的賬號。
創建一個允許用戶從任意地點登錄。這個任意登錄這件事情,雖然我們這樣寫了,一般在公司內允許那一臺機器訪問數據庫可以把這個IP地址確定下來不用填%,今天我們用的云服務器,我們內網經過NAT路由器轉發IP地址會發生改變。本地IP配上去沒有任何意義,所以這里只能用%。

create user 'workbench'@'%' identified by 'xxx';

然后在給新用戶賦權。把conn數據庫所有表的權限都給這個用戶。

grant all on conn.* to 'workbench'@'%';

然后才能遠程連接,點擊這里+,配置一下相關信息

在這里插入圖片描述

我們主要填的就是IP地址,端口號,和用戶。還可以給這個連接起個名字。

在這里插入圖片描述

配置好,然后點擊下面的,代表測試一下連接,它會要求輸入對應的密碼,直接把這個用戶的密碼輸入就行了。

在這里插入圖片描述

如果成功連接在點擊ok就是下面這樣,如果連接不上可能是你端口號沒有放出來。自己放一下。如果想登錄的話,點擊一下這個出來的東西,然后就登錄進去了。

在這里插入圖片描述

進去之后我們可以看到對應表結構、視圖,存儲過程和函數這些。我們現在只用關系表結構就可以了。表結構里面對應的列、索引、外鍵、觸發器這些。

在這里插入圖片描述

列里面可以看到對應列的屬性,如id列的主機和自增長

在這里插入圖片描述

下面我們可以在框里寫一些sql指令了。寫完之后選中或者光標放在你寫的sql這里然后點擊這個閃電執行它。然后下面就可以看到對應的信息。

在這里插入圖片描述

雖然光標放在后面點擊閃電也可以執行,但是它是從上到下開始執行的,如果只需要執行某一個sql指令,還是要選擇它然后在去執行。

在這里插入圖片描述

接下來我們可以一下這個表,可以看到這里擔心數據太多,默認只把0-1000行篩選出來。

在這里插入圖片描述

然后可以直接在這里對數據進行插入,然后再點擊Apply執行一下

在這里插入圖片描述

Apply會把剛剛在圖形化界面這里做的動作變成sql的語句,然后在點Apply執行。

在這里插入圖片描述

然后在點Finsh,這個插入就算真正執行完成了

在這里插入圖片描述

然后我們查一下,確實看到是插入了

在這里插入圖片描述

接下里我們想把張三這條記錄刪除一下,可以直接在圖形化界面刪除,然后還是和上面一樣的流程Apply。

在這里插入圖片描述

然后這看到確實可以刪除。

在這里插入圖片描述

更新也是一樣在圖形化界面改,然后Apply執行一下。我們把李四年齡改成90歲。

在這里插入圖片描述

看到確實也是改了

在這里插入圖片描述

換言之,我們就不用自己寫sql了,拿到表結構對它進行增刪查改,直接在里面手改就行了。這就是圖形化界面的好處。

如果想把自己寫的一大堆sql指令保存一下,可以ctrl+s保存。形成一個.sql文件。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/41320.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/41320.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/41320.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

第9章:Electron的安全性

在開發Electron應用時&#xff0c;安全性是一個非常重要的考慮因素。由于Electron應用可以訪問Node.js的全部API&#xff0c;以及使用Web技術開發界面&#xff0c;因此需要特別注意安全問題。本章將介紹如何提高Electron應用的安全性&#xff0c;包括禁用不必要的功能、設置內容…

Javascript中Object、Array、String

Object 在JavaScript中&#xff0c;Object 類型是一種復雜的數據類型&#xff0c;用于存儲鍵值對集合。它提供了多種方法來操作這些鍵值對&#xff0c;以及執行其他常見的操作。這里&#xff0c;我列出了一些 Object 類型的常見方法或特性&#xff0c;它們在日常編程中非常有用…

開思通智網-科技快報20240704:全球首個,人工智能之城,AI填報志愿

【本周新進展】 天大開發全球首個可開源片上腦機接口智能交互系統 https://tech.opensnn.com/chip/article/2826792 AI系統繪出“多彩”大腦布線圖 https://news.sciencenet.cn/htmlnews/2024/7/525678.shtm 北京亦莊將建全域人工智能之城 https://tech.opensnn.com/chip/arti…

基于深度學習的文本框檢測

基于深度學習的文本框檢測&#xff08;Text Box Detection&#xff09;是一項重要的計算機視覺任務&#xff0c;旨在從圖像中自動檢測和定位文本區域。它在光學字符識別&#xff08;OCR&#xff09;、自動文檔處理、交通標志識別等領域具有廣泛的應用。以下是關于這一領域的系統…

快遞物流運輸中的鎖控系統優缺點探討

一、物流運輸中鎖控系統的重要性 1.1 保障貨物安全 在物流運輸過程中&#xff0c;貨物安全是物流公司最為關注的問題之一。傳統機械鎖雖然在一定程度上提供了安全保障&#xff0c;但其缺點逐漸暴露&#xff0c;成為物流運輸中的一個痛點。 易被破解&#xff1a;傳統機械鎖通…

drawio打開不顯示,不在當前屏幕的解決方案

如果把drawio拖在外接顯示器&#xff0c;關機前沒有拖回主屏幕&#xff0c;那么下次打開它時如果用的不是原來那個顯示器&#xff0c;它就無法正常顯示。在任務欄上能看到有它&#xff0c;但是就是顯示不出來。 經過卸載和其他的方式沒有解決&#xff0c;就想到了&#xff0c;應…

基于MCU平臺的HMI開發的性能優化與實戰(下)

繼上篇《基于MCU平臺的HMI開發的性能優化與實戰&#xff08;上&#xff09;》深入探討了提升MCU平臺HMI開發效率和應用性能的策略后&#xff0c;本文將專注于NXP i.MX RT1170 MCU平臺的儀表盤開發實踐。我們將重點介紹Qt for MCUs的優化技巧&#xff0c;展示如何通過實際案例應…

Qt:7.QWidget屬性介紹(cursor屬性-光標形狀、font屬性-控件文本樣式、tooltip屬性-控件提示信息)

目錄 一、cursor屬性-光標形狀&#xff1a; 1.1cursor屬性介紹&#xff1a; 1.2獲取當前光標形狀——cursor()&#xff1a; 1.3 設置光標的形狀——setCursor()&#xff1a; 1.4 設置自定義圖片為光標&#xff1a; 二、font屬性-控件文本樣式&#xff1a; 2.1font屬性介紹…

antd-Table-可視化數據滾動

代碼 // 使用方式 const Index () > {useScroll();return <Table />; }import { useEffect, useRef, useState } from react;export const useScroll (() > {let timer;function start() {const [isScroll, setIsScroll] useState(true);const scrollTopRef u…

代碼隨想錄算法訓練營Day59|110.字符串接龍、105.有向圖的完全可達性、106.島嶼的周長

字符串接龍 110. 字符串接龍 (kamacoder.com) 主要參考代碼隨想錄 代碼隨想錄 (programmercarl.com) 目標&#xff1a;得到從beginStr轉變為endStr所需的最少步數 過程&#xff1a;每次變換一個字母&#xff0c;每次變換的結果要在strList中。 對于一個圖來說&#xff0c;…

excel批量修改一列單價的金額并保留1位小數

1.打開表格&#xff0c;要把單價金額變成現在的兩倍&#xff0c;數據如下&#xff1a; 2.把單價這一列粘貼到一個新的sheet頁面&#xff0c;在B2單元格輸入公式&#xff1a;A2*2 然后按enter回車鍵,這時候吧鼠標放到B2單元格右下角&#xff0c;會出現一個黑色的小加號&#xf…

重大更新來襲!!《植物大戰僵尸雜交版V2.1+修改器+融合版》

大家好&#xff01;每個軟件更新總是令人興奮不已。前段時間介紹的《植物大戰僵尸》系列以其獨特的策略玩法和豐富的植物角色&#xff0c;贏得了很多玩家的喜愛。而在今天&#xff0c;這款經典游戲全網最新版本——《植物大戰僵尸&#xff1a;雜交版V2.1》正式推出&#xff0c;…

docker 環境下failed to start lsb故障解決

背景&#xff1a;從深信服超融合遷移虛擬機到VMWARE集群后&#xff0c;遷移后的虛擬機 centos 7 運行systemctl start network ,報錯 Restarting network (via systemctl): Job for network.service failed. See systemctl status network.service and journalctl -xn for d…

Redis組建哨兵模式

主172.17.60.131 從172.17.60.130、172.17.60.129 redis部署 [rootlocalhost app]# tar xf redis-6.2.9.tar.gz [rootlocalhost app]# cd redis-6.2.9/ [rootlocalhost redis-6.2.9]# make MALLOClibc [rootlocalhost redis-6.2.9]# make install PREFIX/usr/local/redis…

Docker 中查看及修改 Redis 容器密碼的實用指南

在使用 Docker 部署 Redis 容器時&#xff0c;有時我們需要查看或修改 Redis 的密碼。本文將詳細介紹如何在 Docker 中查看和修改 Redis 容器的密碼&#xff0c;幫助你更好地管理和維護你的 Redis 實例。 一、查看 Redis 容器密碼 通常在啟動 Redis 容器時&#xff0c;我們會…

構建LangChain應用程序的示例代碼:56、如何實現一個多智能體模擬,其中沒有固定的發言順序。智能體自行決定誰來發言,通過競價機制實現

多智能體分散式發言人選擇 示例展示了如何實現一個多智能體模擬,其中沒有固定的發言順序。智能體自行決定誰來發言,通過競價機制實現。 我們將在下面的示例中展示一場虛構的總統辯論來演示這一過程。 導入LangChain相關模塊 from typing import Callable, Listimport tenac…

正向代理反向代理

nginx的正向代理和反向代理: 正向代理以及緩存配置: 代理:客戶端不再是直接訪問服務端&#xff0c;通過代理服務器訪問服務端。 正向代理&#xff1a;面向客戶端&#xff0c;通過代理服務器的ip地址訪問目標服務端 服務端只知道代理服務器的地址&#xff0c;真正的客戶端ip可以…

【MySQL系列】隱式轉換

&#x1f49d;&#x1f49d;&#x1f49d;歡迎來到我的博客&#xff0c;很高興能夠在這里和您見面&#xff01;希望您在這里可以感受到一份輕松愉快的氛圍&#xff0c;不僅可以獲得有趣的內容和知識&#xff0c;也可以暢所欲言、分享您的想法和見解。 推薦:kwan 的首頁,持續學…

ctfshow web入門 nodejs

web334 有個文件下載之后改后綴為zip加壓就可以得到兩個文件 一個文件類似于index.php 還有一個就是登錄密碼登錄成功就有flag username:ctfshow password:123456因為 return name!CTFSHOW && item.username name.toUpperCase() && item.password passwor…

產科管理系統 專科電子病歷系統源碼,前后端分離架構,多家醫院產科廣泛運用,系統穩定,功能齊全

產科管理系統 專科電子病歷系統源碼&#xff0c;前后端分離架構&#xff0c;多家醫院產科廣泛運用&#xff0c;系統穩定&#xff0c;功能齊全 產科管理系統&#xff0c;特別是產科信息管理系統&#xff08;Obstetrical Information Management System&#xff0c;簡稱OIMS&…