目錄
一、前言
二、安裝VMware運行Ubuntu
1.安裝VMware
2.使用VMware打開Ubuntu
三、配置VMware使用網卡
1.添加NAT網卡
四、Linux下安裝MySQL數據庫
五、安裝MySQL開發庫
六、演示代碼
sql_connect.c
sql_connect.h
main.c中數據庫相關代碼
結尾
一、前言
? ? ? ? 由于最近在做項目,需要用到數據庫,想在Linux服務端使用C語言操作MySQL數據庫,于是寫一篇博客記錄一下。希望大伙點個關注支持一下,不久后就更新項目博客。
二、安裝VMware運行Ubuntu
1.安裝VMware
????????Windows 下有很多虛擬機軟件,目前市面上流行的有VMware和VirtualBox。VMware 分為收費專業版 Workstation Pro 和非商用免費版 Workstation?Player,推薦使用Workstation Player。
? ? ? ? 我使用的是韋東山老師提供的 Ubuntu 鏡像文件,鏈接:Linux虛擬機環境?。VMWare 安裝軟件是:VMware-workstation-full-16.2.3-19376536.exe。下面給出VMWare的安裝步驟。
第1步:以管理員身份運行安裝軟件:
第2步:點擊“下一步”:
第3步:勾選“我接受”點擊“下一步”:
第4步:指定安裝目錄后點擊“下一步”:
第5步:設置用戶體驗后點擊“下一步”:
第6步:設置快捷方式后點擊“下一步”:
第7步:點擊“安裝”開始安裝:
第8步:等待安裝完成:
第9步:完成安裝:
????????VMWare 安裝完成后,有兩個軟件,它們都可以使用,建議使用第2個:
????????①?Vmware Workstation Pro:這是收費的,可以試用30天。
????????②?Vmware Workstation 16 Player:這是免費的。
2.使用VMware打開Ubuntu
? ? ? ? 解壓Ubuntu鏡像壓縮包后,可以得到如圖所示文件:
注意:在打開之前,請先確保您的電腦的BIOS已經啟動了虛擬化,可以打開設備管理器確認這點,如圖所示:
? ? ? ? 然后查看是否啟動了虛擬化:
? ? ? ? 確認打開后,就可以使用VMware打開Ubuntu鏡像了:
第1步:以管理員身份打開Vmware Workstation 16 player:
第2步:打開虛擬機,使用vmware打開前面解壓得到的“Ubuntu 18.04_x64.vmx”:
第3步:播放虛擬機:
第4步:第一次啟動Ubuntu時,選擇默認的“我已復制該虛擬機”,啟動后輸入密碼“123456”回車即可登錄:
注意:虛擬機默認沒有開啟小鍵盤,如果使用小鍵盤輸入,請先開啟小鍵盤
三、配置VMware使用網卡
1.添加NAT網卡
????????使用韋東山老師團隊制作的Ubuntu映像時,它已經添加了NAT網卡,無需再添加NAT網卡。如果你的Ubuntu虛擬機中沒有NAT網卡,則可以如圖所示添加NAT網卡:
① 點擊進入“編輯虛擬機設置”;
② 如果沒有NAT模式的網卡,則繼續下一步;
③ 點擊“添加”;
④ 選擇“網絡適配器”;
⑤ 點擊“完成”;
⑥ 設置新添加的“網絡適配器”的“網絡連接”為“NAT模式”;
⑦ 點擊確定完成NAT網卡的添加;
????????添加NAT網卡后,可以啟動Ubuntu,使用 ifconfig 命令查看IP,再使用 ping 命令確認可以連接外網:
? ? ? ? 至此前期的準備工作就結束了!下面準備安裝MySQL數據庫。
四、Linux下安裝MySQL數據庫
????????直接在終端按順序輸入以下命令即可:
sudo apt install mysql-server
????????輸入這個之后會讓我們輸入密碼,也是123456。然后會問我們是否確定安裝,輸入Y即可。
????????安裝完之后會自動啟動MySQL服務,使用下面的命令來查看服務狀態:
systemctl status mysql
????????看到顯示 active 就表示服務已經啟動成功了:
? ? ? ? 如果沒有啟動的可以執行下面命令來啟動:
systemctl start mysql?
? ? ? ? 然后輸入密碼即可。
? ? ? ? 接著我們來修改一下密碼,這個密碼是進入MySQL數據庫的密碼,不是Ubuntu的登陸密碼,不要搞混了,以后我們使用MySQL開發庫,通過C語言來操作數據庫,肯定需要傳入密碼和IP等參數,我們現在就來修改這個密碼。
? ? ? ? Linux系統安裝完之后默認是有密碼的,如果輸入的密碼錯誤,當然也就無法連接到MySQL的服務,輸入以下命令可以找到默認的密碼:
sudo cat /etc/mysql/debian.cnf?
? ? ? ? 通過這個命令可以找到這個位置上的配置文件,它里面就記載了一個默認的用戶名和密碼,那我們就可以使用這個用戶名和密碼來連接MySQL的服務,輸入命令如下:
mysql -u debian-sys-maint -p?m6mhClGDw71Ko2yS?
????????-u 后面是你的用戶名,-p后面是密碼,回車后就能連接到MySQL服務了。但是這個用戶名和密碼都不太好記,現在我們來修改密碼和用戶名,我們輸入了上面那行命令后,已經連接到了MySQL服務,然后輸入下面的語句修改:
alter user 'root'@'%' identified with mysql_native_password by '123456';?
? ? ? ? 如果出錯的話就把%改成localhost,修改成功后執行下面的語句刷新權限:
flush privileges;?
? ? ? ? 之后就可以輸入 mysql -u root -p ,然后輸入密碼?123456?連接MySQL服務了,退出MySQL服務到終端的語句為 exit; 。
五、安裝MySQL開發庫
? ? ? ? 我們要安裝?libmysqlclient-dev?開發庫,這個lib庫是Linux下使用C/C++連接MySQL的客戶端,安裝步驟如下:
? ? ? ? 更新軟件源:
sudo apt update
? ? ? ? 然后直接下載:
sudo apt install libmysqlclient-dev?
? ? ? ? 這樣我們就可以編寫C語言來操作數據庫了,詳細內容可以看這個博主的博客,還是十分詳細的:Linux(程序設計):18---libmysqlclient-dev庫(C語言操作MySQL)-CSDN博客?。
? ? ? ? 注意:編譯的時候需要指定頭文件路徑以及鏈接mysqlclient庫,如下:
gcc demo.c -o demo -I/usr/include/mysql -lmysqlclient
六、演示代碼
? ? ? ? 由于我對數據庫也不是很了解,只學了點皮毛,項目中只用到了數據的插入、修改、刪除和查詢(如果你也是想用C語言對數據庫進行簡單操作,你可以參考我的代碼),下面直接給出我用的代碼給大家參考,我會說明功能和用法:
sql_connect.c
#include "sql_connect.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 初始化數據庫連接對象
SQLifconfig* SQLifconfig_init() {SQLifconfig *config = (SQLifconfig*)malloc(sizeof(SQLifconfig));if (!config) return NULL;// 初始化成員變量config->mysql = NULL;config->row = NULL;config->result = NULL;// 初始化 MySQL 連接config->mysql = mysql_init(NULL);if (!config->mysql) {printf("Init Error: %s\n", mysql_error(config->mysql));free(config);return NULL;}// 強制設置字符集if (mysql_options(config->mysql, MYSQL_SET_CHARSET_NAME, "utf8mb4")) {printf("Set UTF-8 Error: %s\n", mysql_error(config->mysql));mysql_close(config->mysql);free(config);return NULL;}return config;
}// 釋放數據庫連接對象
void SQLifconfig_destroy(SQLifconfig *config) {if (config) {if (config->mysql) {mysql_close(config->mysql);}free(config);}
}// 初始化數據庫連接
bool SQLifconfig_SQL_init(SQLifconfig *config, const char *host, const char *user, const char *pwd, const char *dbname) {if (!mysql_real_connect(config->mysql, host, user, pwd, dbname, 3306, NULL, 0)) {printf("connect error: %s\n", mysql_error(config->mysql));return false;}return true;
}// 執行操作 SQL 語句(INSERT/UPDATE/DELETE)
bool SQLifconfig_Dml_sql(SQLifconfig *config, const char *sqlstr) {printf("sql: %s\n", sqlstr);// 開始事務if (mysql_query(config->mysql, "BEGIN")) {printf("query_error: %s\n", mysql_error(config->mysql));return false;}// 執行 SQL 語句if (mysql_query(config->mysql, sqlstr)) {printf("query_error: %s\n", mysql_error(config->mysql));return false;}// 提交事務if (mysql_query(config->mysql, "COMMIT")) {printf("query_error: %s\n", mysql_error(config->mysql));return false;}return true;
}// 執行查詢 SQL 語句(SELECT)
char* SQLifconfig_Dql_sql(SQLifconfig *config, const char *sqlstr) {// 執行 SQL 查詢if (mysql_query(config->mysql, sqlstr)) {printf("query_error: %s\n", mysql_error(config->mysql));return NULL;}// 獲取查詢結果集config->result = mysql_store_result(config->mysql);if (!config->result) {return NULL; // 無結果或錯誤}// 獲取字段數量int fieldnum = mysql_num_fields(config->result);// 初始化動態緩沖區size_t total_len = 1024; // 初始緩沖區大小char *buffer = (char*)malloc(total_len);if (!buffer) {mysql_free_result(config->result);return NULL; // 內存分配失敗}buffer[0] = '\0'; // 初始化空字符串// 遍歷結果集的每一行while ((config->row = mysql_fetch_row(config->result))) {// 計算當前行所需的總長度size_t row_len = 0;for (int j = 0; j < fieldnum; j++) {row_len += strlen(config->row[j] ? config->row[j] : "NULL") + 1; // 字段值 + 分隔符}// 動態擴展緩沖區(如果當前緩沖區不足以容納新行)size_t current_len = strlen(buffer);if (current_len + row_len + 2 > total_len) {total_len += row_len + 2; // 擴展緩沖區大小char *new_buf = realloc(buffer, total_len);if (!new_buf) {free(buffer);mysql_free_result(config->result);return NULL; // 內存分配失敗}buffer = new_buf;}// 拼接當前行的字段值for (int j = 0; j < fieldnum; j++) {const char *val = config->row[j] ? config->row[j] : "NULL"; // 處理 NULL 值strcat(buffer, val); // 追加字段值strcat(buffer, "#"); // 追加分隔符}buffer[strlen(buffer)-1] = '\n'; // 將最后一個#替換為換行符}// 釋放結果集內存mysql_free_result(config->result);// 檢查是否有有效數據if (strlen(buffer) == 0) {free(buffer);return NULL; // 無數據}// 返回格式化后的字符串return buffer;
}
sql_connect.h
#ifndef __SQL_CONNECT_H
#define __SQL_CONNECT_H#include <mysql.h>
#include <stdbool.h>// 數據庫連接結構體
typedef struct {MYSQL *mysql; // MySQL 連接對象MYSQL_ROW row; // 當前行數據MYSQL_RES *result; // 查詢結果集
} SQLifconfig;// 初始化數據庫連接
SQLifconfig* SQLifconfig_init();// 釋放數據庫連接
void SQLifconfig_destroy(SQLifconfig *config);// 初始化數據庫連接
bool SQLifconfig_SQL_init(SQLifconfig *config, const char *host, const char *user, const char *pwd, const char *dbname);// 執行查詢 SQL 語句(SELECT)
char* SQLifconfig_Dql_sql(SQLifconfig *config, const char *sqlstr);// 執行操作 SQL 語句(INSERT/UPDATE/DELETE)
bool SQLifconfig_Dml_sql(SQLifconfig *config, const char *sqlstr);#endif
main.c中數據庫相關代碼
/*--------------------------*/
/*數據庫初始化相關操作*/
// 初始化數據庫連接對象
SQLifconfig *MySQL_Handler = SQLifconfig_init();
if (!MySQL_Handler)
{printf("初始化數據庫失敗\n");return -1;
}
// 連接數據庫
if (!SQLifconfig_SQL_init(MySQL_Handler, "127.0.0.1", "root", "123456", "testdatabase"))
{printf("連接數據庫失敗\n");SQLifconfig_destroy(MySQL_Handler);return -1;
}
/*--------------------------*//*--------------------------*/
/*查詢數據示例操作*/
char buf[100];
// 構造 SQL 查詢語句
sprintf(buf, "select * from table where id='%s'", str);char *result = SQLifconfig_Dql_sql(MySQL_handler, buf);
if(result)
{printf("查詢到的數據:%s\n", buf);free(result); // 必須手動釋放內存
}
//失敗的話會返回NULL,同時在函數內部已經釋放了內存,因此失敗的分支不需要我們手動釋放了
else
{write(customer->client_socket, "4\n", 2);
}
/*--------------------------*//*--------------------------*/
/*修改數據示例操作*/
char buf[100] = {0};
// 構造 SQL 刪除語句,刪除table表中id為AABBCCDD的一行數據
sprintf(buf, "DELETE FROM table WHERE id='%s'", "AABBCCDD");// 執行 SQL 刪除操作
int result = SQLifconfig_Dml_sql(MySQL_handler, buf);
if(result)
{//成功
}
else
{//失敗
}
/*--------------------------*/
? ? ? ? 其實就是自己構造MySQL語句,可以去看看一些常用的語句,還是比較簡單的,Dql函數會返回查詢到的數據,每個字段都會用 # 分隔,每一行的數據最后還會加上 \n 換行符,比如說我要查詢table中的所有數據,返回值如下:
id#name#level
id2#name2#level2
????????注意這里的每一行的末尾都會有換行符'\n',其中需要注意的是,如果你想查詢表里的某一行數據的某個字段,如果這個位置你還沒有寫過數據,讀出來的值是"NULL\n"字符串,并不是NULL,只有查詢失敗才會返回 NULL,可以仔細看一下我的代碼。
結尾
? ? ? ? 分享到此結束了,后面我會更新Linux下C語言編寫的服務端+Qt管理員端+Qt用戶端+STM32用戶端實現的無人超市項目,也是成功復刻了一個大佬的項目,學到了很多東西,希望大家點個關注支持一下。