一、安裝 MySQL 庫
我們之前學(xué)習(xí)數(shù)據(jù)庫都是在 Linux 的 mysql 客戶端下以純命令行的方式操作的,但其實(shí),我們也可以使用 C/C++/Java/Python 等語言來連接數(shù)據(jù)庫,向 mysqld 下達(dá) sql 語句并獲取執(zhí)行結(jié)果。不過,在這之前,我們需要先安裝 MySQL 對(duì)應(yīng)的庫,這里我們以 C 語言連接數(shù)據(jù)庫為例。
關(guān)于 MySQL 的 C語言庫,我們可以直接到 MySQL 官網(wǎng)中去下載,然后 rz 上傳到 Linux 中解壓。當(dāng)然我們也可以通過 yum 來直接安裝 mysql client 以及 mysql devel,因?yàn)橹拔覀冊(cè)诎惭b mysql-commun-server 時(shí)已經(jīng)配置了 mysql 相關(guān)的 yum 源。(其實(shí)那時(shí)候 mysql client 我們也已經(jīng)安裝了)
安裝完畢后我們就可以在 /usr/include/mysql
目錄下找到 mysql 相關(guān)的頭文件了:
同時(shí),我們也可以在 /lib64/mysql/
以及 /usr/lib64/mysql
目錄下找到 mysql 對(duì)應(yīng)的動(dòng)態(tài)庫以及靜態(tài)庫了:
驗(yàn)證引入是否成功
現(xiàn)在,我們就可以使用 mysql 目錄下頭文件中提供的相關(guān)函數(shù)來連接數(shù)據(jù)庫了。
不過,在正式連接數(shù)據(jù)庫之前,我們可以先通過 mysql_get_client_info() 函數(shù)來驗(yàn)證一下 mysql 相關(guān)頭文件以及動(dòng)態(tài)庫是否被成功引入:
函數(shù)原型:const char *mysql_get_client_info(void);
返回值: A character string that represents the MySQL client library version.
#include <iostream>
#include <mysql/mysql.h>
using namespace std;
int main()
{
cout << "mysql version: " << mysql_get_client_info() << endl;
return 0;
}
這里有幾個(gè)需要注意的地方:
- 由于我們要使用 mysql C庫中的函數(shù),所以在 test.cc 中我們需要包含 mysql 相關(guān)頭文件。
- 在程序編譯時(shí),我們需要使用 -l 選項(xiàng)來指定我們要鏈接的 mysql 動(dòng)態(tài)庫,并且動(dòng)態(tài)庫的庫名稱是去掉前綴 lib 以及后綴 .so 后的剩余部分。(libmysqlclient.so -> mysqlclient)
- 由于動(dòng)態(tài)庫在
/usr/lib64/mysql/
目錄下,而系統(tǒng)的默認(rèn)庫路徑是/usr/lib64/
,所以我們還需要使用 -L 選項(xiàng)來指定動(dòng)態(tài)庫的路徑。 - mysql C語言相關(guān)頭文件在
/usr/include/mysql/
目錄下,而系統(tǒng)默認(rèn)的頭文件搜索路徑是/usr/include/
,所以按道理來說,我們也是需要使用 -I 選項(xiàng)指明頭文件路徑的;但這里由于我們?cè)诰帉懺闯绦颍^文件時(shí)使用的是mysql/mysql.h
,而不僅僅是mysql.h
,所以不需要指定。 - 最后,關(guān)于動(dòng)靜態(tài)庫相關(guān)的知識(shí),我們其實(shí)以前在 Linux 系統(tǒng)編程中講過,有需要的同學(xué)可以再看一下 – 動(dòng)靜態(tài)庫。
二、MySQL C API 相關(guān)接口
1、C API 官方文檔
關(guān)于C語言連接數(shù)據(jù)所涉及到的各種數(shù)據(jù)結(jié)構(gòu)的介紹以及相關(guān)函數(shù)的使用其實(shí)在 MySQL C API 官方文檔中已經(jīng)給出了,我們可以通過它來快速了解并上手 MySQL C API。
2、初始化 MYSQL
要使用 MySQL C語言庫,需要先使用 mysql_init
函數(shù)完成對(duì) MYSQL 結(jié)構(gòu)體指針的初始化工作。
MYSQL *mysql_init(MYSQL *mysql)
- 函數(shù)返回值:失敗返回 NULL。
注意:mysql_init 函數(shù)的參數(shù)以及返回值都是 MYSQL 指針類型,對(duì)于 MYSQL,大家把它類比到C語言中的文件指針來理解即可。MYSQL 和C語言文件 FILE 一樣,本質(zhì)上都是一個(gè)結(jié)構(gòu)體。
MYSQL *mfp = mysql_init(nullptr);
if(mfp == nullptr)
{
cerr << "mysql init error" << endl;
return 1;
}
cout << "mysql init success" << endl;
注意:這里用C語言的 NULL 還是C++的 nullptr 都可以,因?yàn)樗鼈冊(cè)跀?shù)值上都是0;區(qū)別在于在定義時(shí) NULL 是一個(gè)整數(shù),而 nullptr 則是被強(qiáng)轉(zhuǎn)為了 void* 類型。
3、連接 MySQL
初始化完畢后,我們需要使用 mysql_real_connect
函數(shù)來連接數(shù)據(jù)庫。
MYSQL *
mysql_real_connect(MYSQL *mysql, // MYSQL結(jié)構(gòu)體指針對(duì)象
const char *host, // mysqld服務(wù)進(jìn)程所在的主機(jī)
const char *user, // 登錄MySQL的用戶
const char *passwd, // 用戶密碼
const char *db, // 要訪問的數(shù)據(jù)庫
unsigned int port, // mysqld服務(wù)進(jìn)程的端口號(hào)
const char *unix_socket, // 默認(rèn)設(shè)為NULL即可
unsigned long client_flag) // 默認(rèn)設(shè)為0即可
- 函數(shù)返回值:失敗返回0,成功返回傳入的MYSQL指針。
const string host = "127.0.0.1";
const string user = "thj";
const string password = "Abcd1234@";
const string db = "test_connection";
unsigned int port = 4106;
mfp = mysql_real_connect(mfp, host.c_str(), user.c_str(), password.c_str(), db.c_str(), port, nullptr, 0);
if(mfp == nullptr)
{
cerr << "mysql connection error" << endl;
return 2;
}
cout << "mysql connection success" << endl;
其實(shí)從這里我們也可以看出 MYSQL 其實(shí)就是一個(gè)結(jié)構(gòu)體,其中包含了 host、user、port 等字段,我們調(diào)用 mysql_real_connect
函數(shù)時(shí)傳遞的參數(shù)就是用來填充這些字段的。
設(shè)置連接字符集
需要注意的是,我們之前在創(chuàng)建數(shù)據(jù)庫時(shí)默認(rèn)使用的字符集是 utf8
,而C語言連接數(shù)據(jù)時(shí)默認(rèn)的字符集是 latin1
的,這就會(huì)導(dǎo)致我們?cè)谙虮碇胁迦胫形臄?shù)據(jù)時(shí),由于字符集不匹配,最終數(shù)據(jù)庫中存儲(chǔ)的數(shù)據(jù)顯式出來是亂碼。
所以,我們需要使用 mysql_set_character_set
函數(shù)設(shè)置連接字符集為 utf8
。
int mysql_set_character_set(MYSQL *mysql, const char *csname)
- 函數(shù)返回值:返回0表示成功,非0表示失敗。
int n = mysql_set_character_set(mfp, "utf8");
if(n != 0) { cout << "warning: character set fail" << endl; }
4、下發(fā) mysql 指令
在成功連接到數(shù)據(jù)庫之后,我們就可以通過 mysql_query
函數(shù)來下發(fā) mysql 指令了。
int mysql_query(MYSQL *mysql, const char *stmt_str)
- 函數(shù)返回值:執(zhí)行成功返回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;
}
我們可以登錄 msyql 客戶端查看數(shù)據(jù)是否真正被插入:
需要注意的是,我們?cè)谑褂?mysql client 時(shí),一條 sql 語句需要以分號(hào)結(jié)尾;但是在C語言中,sql 語句可以不用帶分號(hào),當(dāng)然帶上也沒事。
5、獲取 mysql 查詢結(jié)果
我們上面是對(duì)數(shù)據(jù)庫執(zhí)行增刪改操作,它們相對(duì)來說比較簡(jiǎn)單,因?yàn)槲覀冎恍枰獙⒅噶钕掳l(fā)給數(shù)據(jù)庫即可,后面的事情我們不必關(guān)心。但如果我們執(zhí)行的是查詢操作,則需要通過 mysql_store_result
函數(shù)來獲取查詢結(jié)果。
MYSQL_RES *mysql_store_result(MYSQL *mysql)
- 函數(shù)返回值:失敗返回 NULL,成功返回一個(gè)非空的 MYSQL_RES 類型的結(jié)構(gòu)體指針。
實(shí)際上,mysql_store_result
函數(shù)會(huì)調(diào)用 MYSQL
結(jié)構(gòu)體變量中的 st_mysql_methods 字段中的 read_rows 函數(shù)指針來獲取查詢的結(jié)果;然后將查詢結(jié)果保存到 MYSQL_RES
結(jié)構(gòu)體中并返回結(jié)構(gòu)體指針。這樣,當(dāng)執(zhí)行完 mysql_store_result 以后,其實(shí)數(shù)據(jù)都已經(jīng)在MYSQL_RES 變量中了,我們直接從中獲取即可。
需要注意的是,MYSQL_RES
是通過 malloc/new 空間的方式來保存查詢結(jié)果的,所以當(dāng)我們使用完畢之后,一定要記得釋放 MYSQL_RES
對(duì)象,否則就會(huì)造成內(nèi)存泄漏。同時(shí),MYSQL_RES 結(jié)構(gòu)體中存在查詢結(jié)果的列數(shù)、列信息、行數(shù)、行內(nèi)容等屬性,我們需要使用對(duì)應(yīng)的函數(shù)來獲取這些信息。
- 獲取結(jié)果列數(shù)。
unsigned int mysql_num_fields(MYSQL_RES *result)
- 獲取結(jié)果中每一列的列屬性。
MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *res);
關(guān)于 MYSQL_FIELD
結(jié)構(gòu)體,它里面包含了列的各種屬性信息,包括列名稱、列類型、列大小、列屬于哪個(gè)表哪個(gè)庫等等。
同時(shí),我們可以通過重復(fù)調(diào)用 mysql_fetch_field
函數(shù)來獲取表中每個(gè)列字段的 MYSQL_FIELD
結(jié)構(gòu),即當(dāng)我們下次再調(diào)用 mysql_fetch_field 函數(shù)時(shí),會(huì)自動(dòng)獲取到表中下一個(gè)列的屬性信息,而不需要我們手動(dòng)指定訪問的是哪一列。這和C++中的迭代器很類似。 這種類似迭代器的功能應(yīng)該是與 MYSQL_RES
中的 current_field
字段有關(guān)。
當(dāng)然,我們也可以通過調(diào)用 mysql_fetch_fields
函數(shù)一次獲取到所有列的屬性信息,然后分別打印。
MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res);
- 獲取結(jié)果行數(shù)。
my_ulonglong mysql_num_rows(MYSQL_RES *result)
- 獲取結(jié)果中每一行的具體內(nèi)容。
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)
MYSQL_ROW
本質(zhì)上其實(shí)是一個(gè)二級(jí)指針,我們可以把它當(dāng)作一個(gè)一級(jí)指針數(shù)組來看待,數(shù)組中的每個(gè)元素都是一級(jí)指針。同時(shí),由于 MYSQL_RES
中保存的是查詢到的多行結(jié)果,所以我們可以將 MYSQL_RES
看作是一個(gè)二級(jí)指針數(shù)組,數(shù)組中的每個(gè)元素都是二級(jí)指針 (MYSQL_ROW)。
如上,將 MYSQL_RES 當(dāng)作一個(gè)二維數(shù)組,那么 MYSQL_RES 中的每一個(gè)元素就代表查詢結(jié)果中的一行數(shù)據(jù) (不包含屬性行),這行數(shù)據(jù)是一個(gè)一維數(shù)組,且數(shù)組中的每個(gè)元素都是 char* 類型 (mysql 在讀取數(shù)據(jù)時(shí)會(huì)將所有的數(shù)據(jù)都當(dāng)作字符串)。這樣,我們就可以先使用 mysql_num_rows 和 mysql_num_fields 獲取到結(jié)果集的行數(shù)和列數(shù),然后以遍歷二維數(shù)組的方式即可獲取到全部行的內(nèi)容了。
具體示例如下:
// 下發(fā)mysql指令 -- 查詢
string sql = "select * from user";
if (mysql_query(mfp, sql.c_str()) != 0)
{
cout << sql << " fail" << endl;
}
else cout << sql << " success" << endl;
// 將查詢結(jié)果轉(zhuǎn)儲(chǔ)到MYSQL_RES中
MYSQL_RES *res = mysql_store_result(mfp);
if(res == nullptr)
{
cerr << "store query result error" << endl;
return 3;
}
// 獲取結(jié)果集的行數(shù)與列數(shù)
size_t rowCount = mysql_num_rows(res);
size_t colCount = mysql_num_fields(res);
// 打印列屬性信息 -- 一次獲取單列
for(int i = 0; i < colCount; i++)
{
// 一個(gè)列字段的所有屬性 -- 自動(dòng)迭代
MYSQL_FIELD *field = mysql_fetch_field(res);
cout << field->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;
// 打印結(jié)果集中的行內(nèi)容
for(int i = 0; i < rowCount; i++)
{
// 一行的所有內(nèi)容 -- 自動(dòng)迭代
MYSQL_ROW row = mysql_fetch_row(res);
for(int j = 0; j < colCount; j++)
{
// 一行內(nèi)容中的某一列的內(nèi)容
cout << row[j] << '\t';
}
cout << endl;
}
6、釋放 MYSQL_RES 對(duì)象
由于 MYSQL_RES 保存查詢結(jié)果的空間是通過 malloc/new 得到的,所以當(dāng)我們使用完畢后需要釋放掉 MYSQL_RES 對(duì)象,防止內(nèi)存泄露。
void mysql_free_result(MYSQL_RES *result)
mysql_free_result(res);
7、關(guān)閉 MySQL 連接
最后,當(dāng)我們使用完 MySQL 后,需要關(guān)閉 MySQL 之前建立的連接。
void mysql_close(MYSQL *sock);
mysql_close(mfp);
8、MySQL 其他操作
除了上述這些操作外,MySQL C API 還支持事務(wù)、回滾等常見操作,感興趣的同學(xué)可以了解一下。
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);
9、總結(jié)
使用 MySQL C API 連接數(shù)據(jù)庫進(jìn)行簡(jiǎn)單操作的步驟如下:
- 初始化 MYSQL 結(jié)構(gòu)體指針 – mysql_init。
- 連接 MySQL – mysql_real_connect:需要指定數(shù)據(jù)庫服務(wù)所在主機(jī)、端口以及登錄mysql的用戶和密碼等信息。
- 下發(fā) MySQL 指令 – mysql_query。
- 獲取 MySQL 查詢結(jié)果:將查詢結(jié)果轉(zhuǎn)儲(chǔ)到 MYSQL_RES 中 – mysql_store_result,獲取查詢結(jié)果的行數(shù) – mysql_num_rows,獲取查詢結(jié)果列數(shù) – mysql_num_fields,獲取單個(gè)/所有列字段的 MYSQL_FIELD 屬性信息 – mysql_fetch_field/mysql_fetch_fields,獲取查詢結(jié)果單行的內(nèi)容 (不包含屬性行) – mysql_fetch_row。
- 釋放 MYSQL_RES 對(duì)象 – mysql_free_result。
- 關(guān)閉 MySQL 連接 – mysql_close。
#include <iostream>
#include <mysql/mysql.h>
using namespace std;
int main()
{
// 驗(yàn)證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;
// 連接數(shù)據(jù)庫
const string host = "127.0.0.1";
const string user = "thj";
const string password = "Abcd1234@";
const string db = "test_connection";
unsigned int port = 4106;
mfp = mysql_real_connect(mfp, host.c_str(), user.c_str(), password.c_str(), db.c_str(), port, nullptr, 0);
if(mfp == nullptr)
{
cerr << "mysql connection error" << endl;
return 2;
}
cout << "mysql connection success" << endl;
// 設(shè)置連接字符集
int n = mysql_set_character_set(mfp, "utf8");
if(n != 0) { cout << "warning: character set fail" << endl; }
// 下發(fā)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;
// }
// 下發(fā)mysql指令 -- 查詢
string sql = "select * from user";
if (mysql_query(mfp, sql.c_str()) != 0)
{
cout << sql << " fail" << endl;
}
else cout << sql << " success" << endl;
// 將查詢結(jié)果轉(zhuǎn)儲(chǔ)到MYSQL_RES中
MYSQL_RES *res = mysql_store_result(mfp);
if(res == nullptr)
{
cerr << "store query result error" << endl;
return 3;
}
// 獲取結(jié)果集的行數(shù)與列數(shù)
size_t rowCount = mysql_num_rows(res);
size_t colCount = mysql_num_fields(res);
// 打印列屬性信息 -- 一次獲取單列
for(int i = 0; i < colCount; i++)
{
// 一個(gè)列字段的所有屬性 -- 自動(dòng)迭代
MYSQL_FIELD *field = mysql_fetch_field(res);
cout << field->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;
// 打印結(jié)果集中的行內(nèi)容
for(int i = 0; i < rowCount; i++)
{
// 一行的所有內(nèi)容 -- 自動(dòng)迭代
MYSQL_ROW row = mysql_fetch_row(res);
for(int j = 0; j < colCount; j++)
{
// 一行內(nèi)容中的某一列的內(nèi)容
cout << row[j] << '\t';
}
cout << endl;
}
// 釋放MYSQL_RES對(duì)象
mysql_free_result(res);
// 關(guān)閉數(shù)據(jù)庫連接
mysql_close(mfp);
return 0;
}
三、使用圖形化工具連接 MySQL
其實(shí)除了使用各種編程語言來連接數(shù)據(jù)庫之外,在實(shí)際開發(fā)中另一種比較常用的方式是使用圖形化工具來連接數(shù)據(jù)庫。
市場(chǎng)上關(guān)于 MySQL 的圖形化工具有很多,其中比較優(yōu)秀的是 Navicat 和 SQLyog,但他們都是收費(fèi)的,當(dāng)然如果個(gè)人使用的話可以在網(wǎng)上下載破解版的。免費(fèi)的工具也有很多,但大都不怎么好用,在免費(fèi)工具中表現(xiàn)比較優(yōu)秀的是 MySQL 官方開發(fā)的 Workbench。如果大家有興趣的話可以去嘗試一下,這里我僅僅簡(jiǎn)單提一下。文章來源:http://www.zghlxwxcb.cn/news/detail-718847.html
相關(guān)文章閱讀推薦:https://blog.csdn.net/wpc2018/article/details/122862956文章來源地址http://www.zghlxwxcb.cn/news/detail-718847.html
到了這里,關(guān)于【MySQL】C語言連接數(shù)據(jù)庫的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!