目錄
一,下載庫
二,安裝庫
三,使用庫
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;
}
?