Linux下的c/c++開發之操作mysql數據庫

libmysqlclient-dev介紹(Linux 下的 Mysql C/C++ 開發包)

libmysqlclient-dev 是一個開發包,在Linux環境下為使用 MySQL C API 進行開發的c/c++程序員提供頭文件(如 mysql.h)和靜態庫/動態庫的鏈接信息(如 libmysqlclient.so)。

它是 MySQL 客戶端庫 libmysqlclient 的開發版本,不提供運行時功能,而是用于編譯和構建你的程序。

libmysqlclient-dev包含的內容:

類別路徑或文件名說明
頭文件/usr/include/mysql/mysql.h主頭文件,聲明了所有 MySQL C API 接口函數,如 mysql_init()
/usr/include/mysql/mysql_version.h定義 MySQL 的版本號和宏,如 MYSQL_VERSION_ID
/usr/include/mysql/my_list.h定義鏈表結構,主要用于 MySQL 內部實現
動態庫/usr/lib/x86_64-linux-gnu/libmysqlclient.so動態鏈接庫,編譯時使用 -lmysqlclient 鏈接,運行時動態加載
靜態庫/usr/lib/x86_64-linux-gnu/libmysqlclient.a靜態鏈接庫,將庫打包進可執行文件中(較少使用)
搜索路徑/usr/include/mysql/MySQL C API 所有頭文件所在目錄,編譯時通常用 -I 指定
符號鏈接/usr/lib/x86_64-linux-gnu/libmysqlclient.so -> libmysqlclient.so.X.Y.Z指向具體版本庫文件的符號鏈接,供 -lmysqlclient 查找使用

libmysqlclient-dev的安裝

sudo apt install libmysqlclient-dev

安裝成功后的簡單示例:

test_mysql.c

#include <mysql/mysql.h>
#include <stdio.h>int main() {MYSQL* conn = mysql_init(NULL);if (!conn) {printf("Init failed\n");return 1;}printf("libmysqlclient 初始化成功\n");mysql_close(conn);return 0;
}

編譯:

gcc test_mysql.c -o test_mysql -lmysqlclient

<mysql.h>介紹

<mysql.h>MySQL C API(libmysqlclient)的主頭文件,它提供了訪問 MySQL 數據庫服務器所需的全部函數、宏、結構體和常量。

它是 C/C++ 中與 MySQL 數據庫交互的底層接口,你可以用它完成:

  • 建立數據庫連接

  • 執行 SQL 查詢

  • 獲取查詢結果

  • 處理錯誤

  • 管理事務等

<mysql.h>中的結構體

常用結構體簡介

結構體名類型作用描述使用場景舉例
MYSQL連接對象表示一個與數據庫的連接句柄,初始化、連接、關閉等操作都依賴它mysql_initmysql_real_connect → 查詢/斷開
MYSQL_RES結果集對象表示一次查詢后的結果集(SELECT 返回的所有數據)mysql_store_result / mysql_use_result 得到的結果集
MYSQL_ROW行數據表示查詢結果中的一行,每一列是一個 char*,組成一個 char**遍歷結果集時使用 mysql_fetch_row 得到每一行
MYSQL_FIELD字段描述表示表結構中一列的元信息(列名、類型、長度等)查詢字段信息用 mysql_fetch_fields() 獲取數組
MYSQL_STMT預處理語句句柄表示一條準備執行的 SQL 預處理語句(prepared statement)用于 mysql_stmt_prepare, mysql_stmt_execute 等流程
MYSQL_BIND參數綁定對象用于綁定預處理語句的輸入參數或輸出結果列配合 mysql_stmt_bind_param / mysql_stmt_bind_result 使用
MYSQL_TIME時間結構體表示日期和時間,適用于綁定時間類型字段MYSQL_BIND 中處理 DATETIME / DATE 等類型字段

MYSQL

MYSQL?表示一個數據庫連接句柄。它包含了與數據庫交互的所有必要信息,包括連接參數、狀態、通信通道等。通過 MYSQL 結構體,開發者可以管理數據庫連接、執行查詢、獲取結果等。

MYSQL結構體的定義

typedef struct MYSQL {NET net;                       // 通信參數unsigned char *connector_fd;  // 用于 SSL 的連接器文件描述符char *host;                   // 主機名char *user;                   // 用戶名char *passwd;                 // 密碼char *unix_socket;            // Unix 域套接字路徑char *server_version;         // 服務器版本char *host_info;              // 主機信息char *info;                   // 執行信息char *db;                     // 當前選擇的數據庫struct CHARSET_INFO *charset;// 字符集信息MYSQL_FIELD *fields;          // 字段數組指針struct MEM_ROOT *field_alloc;// 用于字段分配的內存池uint64_t affected_rows;       // 最近一次操作影響的行數uint64_t insert_id;           // 插入操作返回的自增IDuint64_t extra_info;          // 未使用的擴展信息unsigned long thread_id;      // 服務器端的線程IDunsigned long packet_length;  // 包長度unsigned int port;            // 服務器端口unsigned long client_flag;    // 客戶端標志unsigned long 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;          // 當前連接狀態enum enum_resultset_metadata resultset_metadata; // 結果集元數據狀態bool free_me;                // 是否在 mysql_close 時釋放bool reconnect;              // 是否自動重連char scramble[SCRAMBLE_LENGTH + 1]; // 會話級隨機字符串LIST *stmts;                      // 所有預處理語句的鏈表const struct MYSQL_METHODS *methods; // 連接使用的方法集合void *thd;                        // 線程句柄(MySQL 內部線程上下文)bool *unbuffered_fetch_owner;    // 指向 MYSQL_RES 或 MYSQL_STMT 中的標志位,用于取消未緩沖結果集void *extension;                 // 擴展字段,供插件或其他擴展使用
} MYSQL;

?示例:

int main() {MYSQL *conn = mysql_init(nullptr);  // 初始化 MYSQL 結構體// 建立連接(參數:host, user, password, db, port, unix_socket, client_flag)if (!mysql_real_connect(conn, "localhost", "root", "123456", "testdb", 3306, nullptr, 0)) {std::cerr << "Connection failed: " << mysql_error(conn) << std::endl;return 1;}
}

此時的conn

| conn字段             描述                                              
| ------------------ | ----------------------------------------------- 
| `host`             | `localhost`:連接的主機名或 IP。                         
| `user`             | `root`:連接使用的用戶名。                               
| `passwd`           | `123456`:連接使用的密碼。                               
| `unix_socket`      | `nullptr`:Unix socket 文件路徑(僅在使用 socket 連接時有值)。  
| `port`             | `3306`:連接的端口號。                                  
| `protocol_version` | `10`:MySQL 協議版本。                                

MYSQL_TIME

MYSQL_TIME 結構體在 MySQL 客戶端庫中用于表示日期和時間數據。它包含了日期、時間、時區等信息,常用于存儲和處理 MySQL 數據庫中涉及日期、時間、時間戳等類型的數據。

MYSQL_TIME結構體的定義

typedef struct MYSQL_TIME {unsigned int year;      // 年份unsigned int month;     // 月份(1-12)unsigned int day;       // 日(1-31)unsigned int hour;      // 小時(0-23)unsigned int minute;    // 分鐘(0-59)unsigned int second;    // 秒數(0-59)unsigned long second_part; // 微秒部分(0-999999)bool neg;               // 是否為負時間(僅限 TIME 類型)enum enum_mysql_timestamp_type time_type; // 時間類型(如 DATE、DATETIME、TIME)int time_zone_displacement; // 時區偏移(單位:秒)
} MYSQL_TIME;

MYSQL_FIELD

MYSQL_FIELD 結構體是 MySQL 客戶端庫中用于描述數據庫中表的字段(列)的元數據結構。它包含了關于數據庫表列的詳細信息,如列的名稱、數據類型、長度、是否允許為 NULL 等。這個結構體是執行查詢時,檢索列信息的關鍵部分。

MYSQL_RES結構體的定義

typedef struct MYSQL_FIELD {char *name;               // 列名char *org_name;           // 原始列名(如果使用了別名)char *table;              // 所在表名(如果該列來源于表字段)char *org_table;          // 原始表名(如果使用了表別名)char *db;                 // 所在數據庫名char *catalog;            // 所在目錄名(一般為 "def")char *def;                // 默認值(由 mysql_list_fields 設置)unsigned long length;     // 列寬(創建時指定的長度)unsigned long max_length; // 當前查詢結果中該字段的最大長度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;         // 字段標志(如是否為主鍵、自增等)unsigned int decimals;      // 小數位數(針對浮點數類型)unsigned int charsetnr;     // 使用的字符集編號enum enum_field_types type; // 字段類型(定義在 mysql_com.h 中)void *extension;            // 擴展字段(用于內部用途)
} MYSQL_FIELD;

?假設我們有一個實際的數據庫表,名為 users,它包含如下字段:

| id | name  | age | created\_at         |
| -- | ----- | --- | ------------------- |
| 1  | Alice | 30  | 2025-05-01 10:00:00 |
| 2  | Bob   | 25  | 2025-05-02 14:30:00 |

?MYSQL_FIELD 結構體存儲的內容:

| `MYSQL_FIELD` 字段 | 描述                               
| ----------------   | -------------------------------- 
| `name`             | "id"                             
| `org_name`         | "id"                            
| `table`            | "users"                          
| `org_table`        | "users"                          
| `db`               | "my\_database"                   
| `length`           | 11 (表示列寬度,對于整數類型可以是字符寬度)         
| `max_length`       | 11 (最大值,可能是查詢返回時的最大寬度)           
| `type`             | `MYSQL_TYPE_LONG` (表示該列數據類型是長整型) 
| `flags`            | `NOT_NULL` (表明該列不允許為 `NULL`)     
| `decimals`         | 0                                
| `charsetnr`        | `CHARSET_UTF8` (表示字符集)           

MYSQL_RES

用于表示查詢結果的一個數據結構。它包含了從數據庫中查詢得到的所有結果集數據。在執行查詢操作時,MySQL 會返回一個 MYSQL_RES 對象,里面保存了查詢的字段信息、行數據以及與結果相關的其他信息。通過 MYSQL_RES 結構體,我們可以訪問到結果集的元數據(如列信息)以及具體的行數據。

MYSQL_RES結構體的定義

typedef struct MYSQL_RES {uint64_t row_count;                  // 查詢結果中的總行數MYSQL_FIELD *fields;                // 指向字段(列)描述信息數組struct MYSQL_DATA *data;           // 實際的查詢結果數據MYSQL_ROWS *data_cursor;           // 當前讀取到的結果行指針unsigned long *lengths;            // 當前行中每個字段的長度數組MYSQL *handle;                     // 對應的 MYSQL 連接句柄,用于非緩沖讀取const struct MYSQL_METHODS *methods; // 內部使用的方法表指針MYSQL_ROW row;                     // 當前讀取的行數據(非緩沖模式)MYSQL_ROW current_row;             // 當前行緩沖區(緩沖模式)struct MEM_ROOT *field_alloc;     // 用于字段描述信息的內存分配器unsigned int field_count, current_field; // 字段總數,當前字段索引bool eof;                          // 指示是否已到達結果集末尾(用于 mysql_fetch_row)bool unbuffered_fetch_cancelled;  // 標記是否被 mysql_stmt_close 取消enum enum_resultset_metadata metadata; // 結果集的元數據類型void *extension;                   // 擴展字段(MySQL 內部使用)
} MYSQL_RES;

?假設我們有一個名為 users 的數據庫表,結構如下:

| id | name  | age | created\_at         |
| -- | ----- | --- | ------------------- |
| 1  | Alice | 30  | 2025-05-01 10:00:00 |
| 2  | Bob   | 25  | 2025-05-02 14:30:00 |

?假設我們執行的 SQL 查詢:

SELECT id, name, age, created_at FROM users;

查詢結果如下:

| id | name  | age | created\_at         |
| -- | ----- | --- | ------------------- |
| 1  | Alice | 30  | 2025-05-01 10:00:00 |
| 2  | Bob   | 25  | 2025-05-02 14:30:00 |

MYSQL_RES 結構體存儲的內容:

| `MYSQL_RES` 字段             | 描述                                                                                    |
| ---------------------------- | ----------------------------------------------------------
| `row_count`                  | 2 (表示查詢結果中的行數,這里有 2 行數據)                                                              | `fields`                     | 指向一個包含 4 個 `MYSQL_FIELD` 結構體的數組,分別表示 `id`、      `name`、`age` 和 `created_at` 四個字段。   | `data_cursor`                | 用于遍歷查詢結果的指針,指向當前行數據。                                                                  | `lengths`                    | 指向一個數組,存儲每一列數據的長度。例如:`[11, 50, 3, 19]`, 分別表示 `id`、`name`、`age` 和 `created_at`字段的字符長度。| `handle`                     | 指向當前 MySQL 連接的句柄,用于標識與 MySQL 數據庫的連接。                                                  | `methods`                    | 指向包含處理查詢結果方法的結構體,如 `fetch_row`。                                                       | `row`                        | 當使用非緩沖查詢時,指向當前行數據。                                                                    | `current_row`                | 用于存儲當前讀取的行數據。                                                                         | `field_count`                | 表示查詢結果中字段的數量,這里是 4。                                                                   | `eof`                        | 表示查詢結果是否已經讀取到末尾。當所有行數據都被讀取后`true`。                                                  | `unbuffered_fetch_cancelled` | 如果查詢是未緩沖查詢且結果已被取消,則為 `true`。                                                          | `metadata`                   | 用于存儲查詢結果集的元數據。                                                                        

MYSQL_BIND

MYSQL_BIND 結構體主要用于處理 MySQL 準備語句(Prepared Statements)的輸入參數和輸出結果的綁定。通過使用 MYSQL_BIND,你可以將輸入參數傳遞給 MySQL 并從數據庫中獲取查詢結果。它在與 MYSQL_STMT 結構體結合時,提供了參數綁定功能,用于執行具有參數化查詢的 SQL 語句。

作用:

  • 輸入參數綁定:當執行 INSERTUPDATE 等操作時,MYSQL_BIND 結構體可以將 C 語言的變量與 SQL 語句的參數進行綁定。你將一個 C 語言的變量傳遞給 MySQL,MySQL 執行查詢時會使用這個變量的值。

  • 輸出結果綁定:當執行 SELECT 查詢時,查詢結果的列可以通過 MYSQL_BIND 結構體與 C 語言中的變量綁定,將查詢結果存儲到相應的變量中。

?MYSQL_BIND結構體的定義

typedef struct MYSQL_BIND {unsigned long *length; // 指向輸出數據長度的指針(用于接收時獲取實際長度)bool *is_null;         // 指向是否為 NULL 的標志指針void *buffer;          // 實際存放或讀取數據的緩沖區指針bool *error;           // 如果在取數據時發生截斷,用于記錄是否出錯的標志指針unsigned char *row_ptr; // 當前數據在行緩沖區中的位置指針void (*store_param_func)(NET *net, struct MYSQL_BIND *param); // 發送參數到服務器時使用的函數指針void (*fetch_result)(struct MYSQL_BIND *, MYSQL_FIELD *, unsigned char **row); // 從服務器讀取結果時的處理函數void (*skip_result)(struct MYSQL_BIND *, MYSQL_FIELD *, unsigned char **row);  // 跳過結果時的處理函數unsigned long buffer_length;       // buffer 的長度(取字符串或二進制類型時必須設置)unsigned long offset;              // 用于字符串或二進制類型的偏移讀取位置unsigned long length_value;        // 如果 length 指針為空,則使用此值表示長度unsigned int param_number;         // 參數編號(用于錯誤消息或統計)unsigned int pack_length;          // 內部使用的打包數據長度enum enum_field_types buffer_type; // 緩沖區中數據的類型(如 MYSQL_TYPE_STRING 等)bool error_value;                  // 當 error 為 NULL 時使用此字段表示錯誤bool is_unsigned;                  // 若為無符號整數類型,則此字段為 truebool long_data_used;               // 如果調用過 mysql_send_long_data,則此字段為 truebool is_null_value;                // 當 is_null 為 NULL 時使用此字段表示是否為 NULLvoid *extension;                   // 擴展字段,供 MySQL 內部使用
} MYSQL_BIND;

?輸入參數綁定示例:

在這個例子中,我們將數據插入到一個名為 users 的表中。假設 users 表有兩個字段:idname。我們通過 MYSQL_BIND 結構體綁定輸入參數。

| id | name  |
| -- | ----- |
| 1  | Alice |
int main() {MYSQL *conn;MYSQL_STMT *stmt;MYSQL_BIND bind[2];// 假設已經連接到數據庫// 準備 SQL 查詢語句const char *query = "INSERT INTO users (id, name) VALUES (?, ?)";// 初始化 MYSQL_STMTstmt = mysql_stmt_init(conn);// 設置 id 和 name 的值unsigned long id = 2;char name[50] = "Bob";// 清空綁定數組memset(bind, 0, sizeof(bind));// 綁定 id 參數bind[0].buffer_type = MYSQL_TYPE_LONG; // 類型是 LONGbind[0].buffer = (char *)&id;          // 綁定值bind[0].is_null = 0;                   // 表示參數非 NULL// 綁定 name 參數bind[1].buffer_type = MYSQL_TYPE_STRING; // 類型是 STRINGbind[1].buffer = (char *)name;           // 綁定值bind[1].buffer_length = sizeof(name);    // 字符串長度bind[1].is_null = 0;                    // 表示參數非 NULL// 將綁定的參數應用到語句中mysql_stmt_bind_param(stmt, bind);..........return 0;
}

?輸出參數綁定示例:?

在這個例子中,我們從名為 users 的表中查詢數據。假設 users 表有兩個字段:idname。我們將通過 MYSQL_BIND 結構體綁定輸出參數,并從查詢結果中獲取數據。

| id | name  |
| -- | ----- |
| 1  | Alice |
int main() {MYSQL *conn;MYSQL_STMT *stmt;MYSQL_BIND bind[2]; // 綁定輸出參數// 假設已經連接到數據庫// 準備 SQL 查詢語句const char *query = "SELECT id, name FROM users WHERE id = 1";// 初始化 MYSQL_STMTstmt = mysql_stmt_init(conn);// 設置輸出變量unsigned long output_id;char output_name[50];// 清空綁定數組memset(bind, 0, sizeof(bind));// 綁定輸出參數 idbind[0].buffer_type = MYSQL_TYPE_LONG;  // 類型是 LONGbind[0].buffer = (char *)&output_id;    // 輸出的 id 參數bind[0].is_null = 0;                    // 非 NULLbind[0].length = 0;// 綁定輸出參數 namebind[1].buffer_type = MYSQL_TYPE_STRING; // 類型是 STRINGbind[1].buffer = (char *)output_name;    // 輸出的 name 字符串bind[1].buffer_length = sizeof(output_name); // 輸出緩沖區長度bind[1].is_null = 0;                    // 非 NULLbind[1].length = 0;// 將綁定的輸出參數應用到語句中mysql_stmt_bind_result(stmt, bind); // 綁定輸出參數// 執行查詢mysql_stmt_execute(stmt);return 0;
}

此時bind[2]的結果是:

  bind[0]                      | 描述                                                        |
| ---------------------------- | --------------------------------------------------------- | `buffer_type`                | `MYSQL_TYPE_LONG` (表示 `id` 字段的數據類型是 `LONG`,即整數 類型)         | `buffer`                     | `&output_id` (指向存儲查詢結果的變量的指針,`output_id` 存儲 查詢結果中的 `id` 值) | `is_null`                    | `0`                                         | `length`                     | `0`                             bind[1]                      | 描述                                                        |
| ---------------------------- | --------------------------------------------------------| `buffer_type`                | `MYSQL_TYPE_LONG` (表示 `id` 字段的數據類型是 `LONG`,即整 數類型)    | `buffer`                     | `&output_id` (指向存儲查詢結果的變量的指針,`output_id` 存 儲查詢結果中的 `id` 值) | `is_null`                    | `0`                                           | `length`                     | `0`                                 | `buffer_length`              | `0`                                                        

MYSQL_STMT

MYSQL_STMT 是一個結構體,用來操作預處理 SQL 語句()。你可以把它理解成一個“SQL 執行容器”,你把 SQL 丟進去,把參數綁上去,它幫你執行完,還能幫你取出結果。

舉個最直白的比喻:

想象你開了一家飯店,來了條訂單:

SELECT name, age FROM users WHERE id = ?

這時候:

  • MYSQL_STMT 就像是你廚房里的一口鍋

    • 你先用 mysql_stmt_prepare() 把 SQL(食譜)放進去,這叫“準備鍋”;

    • 然后你往鍋里加料(mysql_stmt_bind_param() 把參數比如 id=100 填進去);

    • 再點火(mysql_stmt_execute() 執行);

    • 然后把煮出來的東西(查詢結果)裝盤(mysql_stmt_bind_result()mysql_stmt_fetch());

    • 用完后洗鍋(mysql_stmt_close())。

它具體做了哪些事?

操作名稱簡單解釋
mysql_stmt_prepare把 SQL 語句編譯好,準備執行(比如預編譯了 SELECT ... WHERE id = ?
mysql_stmt_bind_param把你的輸入參數(例如 id=1)綁定上
mysql_stmt_execute執行語句
mysql_stmt_bind_result把輸出字段綁定到你提供的變量上
mysql_stmt_fetch把結果讀到你綁定的變量里
mysql_stmt_close清理資源、關閉語句

?MYSQL_STMT結構體的定義

typedef struct MYSQL_STMT {struct MEM_ROOT *mem_root; /* 內存分配的根指針 */LIST list;                 /* 用于跟蹤所有語句的列表 */MYSQL *mysql;              /* MySQL 連接句柄 */MYSQL_BIND *params;        /* 輸入參數的綁定 */MYSQL_BIND *bind;          /* 輸出參數的綁定 */MYSQL_FIELD *fields;       /* 結果集元數據 */MYSQL_DATA result;         /* 緩存的結果集 */MYSQL_ROWS *data_cursor;   /* 當前行在緩存數據中的位置 *//*mysql_stmt_fetch() 調用此函數以提取一行數據(不同的提取方式:緩沖、非緩沖、游標提取)。*/int (*read_row_func)(struct MYSQL_STMT *stmt, unsigned char **row); /* 用于提取當前行數據的函數指針 *//* 語句執行后的 mysql->affected_rows 的副本 */uint64_t affected_rows;uint64_t insert_id;          /* mysql->insert_id 的副本 */unsigned long stmt_id;       /* 預處理語句的 ID */unsigned long flags;         /* 游標類型等標志 */unsigned long prefetch_rows; /* 每次 COM_FETCH 提取的行數 *//*從執行/提取后 mysql->server_status 復制,用于獲取服務器端游標狀態。*/unsigned int server_status;unsigned int last_errno;            /* 錯誤碼 */unsigned int param_count;           /* 輸入參數的數量 */unsigned int field_count;           /* 結果集的列數 */enum enum_mysql_stmt_state state;   /* 語句狀態 */char last_error[MYSQL_ERRMSG_SIZE]; /* 錯誤信息 */char sqlstate[SQLSTATE_LENGTH + 1]; /* SQL 錯誤狀態碼 *//* 輸入參數類型是否已發送到服務器 */bool send_types_to_server;bool bind_param_done;           /* 輸入緩沖區已提供 */unsigned char bind_result_done; /* 輸出緩沖區已提供 *//* 如果 mysql_stmt_close() 必須取消此結果,則為 true */bool unbuffered_fetch_cancelled;/*如果需要在執行 mysql_stmt_store_result 時計算 field->max_length,則此字段設置為 true。*/bool update_max_length;struct MYSQL_STMT_EXT *extension; /* 擴展字段,供 MySQL 內部使用 */
} MYSQL_STMT;

示例:

//假設已經連接好了
// 初始化語句
MYSQL_STMT *stmt = mysql_stmt_init(conn);// 準備 SQL(? 是參數占位符)
const char *sql = "SELECT name FROM users WHERE id = ?";
mysql_stmt_prepare(stmt, sql, strlen(sql));// 輸入參數綁定
MYSQL_BIND param;
int user_id = 1;
memset(&param, 0, sizeof(param));
param.buffer_type = MYSQL_TYPE_LONG;
param.buffer = &user_id;
mysql_stmt_bind_param(stmt, &param);// 執行語句
mysql_stmt_execute(stmt);// 結果綁定
MYSQL_BIND result;
char name[50];
unsigned long length;
memset(&result, 0, sizeof(result));
result.buffer_type = MYSQL_TYPE_STRING;
result.buffer = name;
result.buffer_length = sizeof(name);
result.length = &length;
mysql_stmt_bind_result(stmt, &result);// 釋放資源
mysql_stmt_close(stmt);
mysql_close(conn);

此時的stmt為:

| stmt                 | 示例值 / 狀態                    |           描述                           
| -------------------- | --------------------------------| ---------------------------- |
| `mysql`              | 指向連接句柄(非空)                     | 當前已連接到 MySQL 數據庫。 | `query`              | `"SELECT name FROM users WHERE id = ?"` | 原始 SQL 查詢語句。                 | `param_count`        | `1`                              | 只有一個輸入參數,即 `id`。             | `bind_param`         | 指向綁定了 `user_id = 1` 的 `MYSQL_BIND` 結構體  | 輸入參數已綁定。                     | `bind_result`        | 指向綁定了 `name` 輸出緩沖區的 `MYSQL_BIND` 結構體 | 輸出參數已綁定。                     | `state`              | `STMT_EXECUTED`                         | 表示語句已執行。                          |
| `insert_id`          | `0`(無插入)                      | 對 INSERT 語句有效。               |
| `error / last_errno` | `0`(無錯誤)                      | 若執行出錯將有錯誤碼和信息。               |
| `data_cursor`        | 指向當前行數據(非空)    | `mysql_stmt_fetch` 后用于遍歷結果行。 
| `read_buffer`        | 內部分配                 | 存儲查詢返回的行數據內容。                |

<mysql.h>中常用的方法

1. 初始化與連接管理

mysql_init

用于初始化一個 MYSQL 結構體,為后續建立數據庫連接做準備。它是使用 MySQL C API 的第一步。

MYSQL* mysql_init(MYSQL* mysql);

參數:

?mysql:一個 MYSQL 指針,可以是已分配的結構體,也可以傳 NULL(推薦傳 NULL,由庫自動分配)。

返回值:

  • 成功:返回初始化后的 MYSQL * 指針。

  • 失敗:返回 NULL(通常是因為內存不足)。

mysql_real_connect

建立一個真實的數據庫連接。需要傳入主機地址、用戶名、密碼、數據庫名等信息。

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

參數:

  • mysql:由 mysql_init() 初始化的連接句柄。

  • host:數據庫服務器地址,如 "localhost"

  • user:用戶名。

  • passwd:密碼。

  • db:默認連接的數據庫名(可為 NULL)。

  • port:端口號,默認 MySQL 為 3306。

  • unix_socket:Unix socket 文件路徑,Linux 中可用,Windows 可傳 NULL

  • client_flag:用于控制連接行為的標志位,如:

    • 0:默認連接方式。

    • CLIENT_MULTI_STATEMENTS:支持多語句執行。

    • CLIENT_SSL:啟用 SSL 等。

返回值:

  • 成功:返回 MYSQL * 指針,表示連接成功。

  • 失敗:返回 NULL,調用 mysql_error() 查看錯誤信息。

mysql_close

用于關閉一個已建立的數據庫連接并釋放資源,通常在程序結束時調用。

void mysql_close(MYSQL *mysql);

參數:

  • mysql:由 mysql_init()mysql_real_connect() 獲得的連接句柄。

返回值:

  • 無返回值,調用后連接資源被釋放。

mysql_error

當連接或操作失敗時,用于獲取最近發生的錯誤信息(字符串形式)。

const char *mysql_error(MYSQL *mysql);

參數:

  • mysql:連接句柄。

返回值:

  • 返回最近一次 MySQL 操作失敗的錯誤信息字符串。

示例

#include <mysql/mysql.h>
#include <iostream>int main() {// 初始化連接MYSQL *conn = mysql_init(NULL);if (conn == NULL) {std::cerr << "mysql_init() failed\n";return 1;}// 建立連接if (mysql_real_connect(conn, "localhost", "root", "123456", "testdb", 3306, NULL, 0) == NULL) {std::cerr << "mysql_real_connect() failed: " << mysql_error(conn) << "\n";mysql_close(conn); // 即使連接失敗,也要釋放句柄return 1;}std::cout << "Connected to database successfully!" << std::endl;// 關閉連接mysql_close(conn);return 0;
}

mysql_options

用于在連接建立之前為MYSQL*連接句柄設置參數,比如超時、字符集、重連等。

int mysql_options(MYSQL *mysql, enum mysql_option option, const void *arg);

參數:

  • mysql:連接句柄(mysql_init 初始化后)。

  • option:選項類型,如:

    • MYSQL_OPT_CONNECT_TIMEOUT

    • MYSQL_SET_CHARSET_NAME

    • 這里不一一列出,具體參考mysql.h中的定義

  • arg:指向具體的設置值,如字符集名 "utf8mb4"

返回值:

  • 0:成功。

  • 非 0:失敗。

mysql_set_character_set

連接成功后,設置當前連接使用的字符集。

int mysql_set_character_set(MYSQL *mysql, const char *csname);

參數:

  • mysql:連接句柄。

  • csname:字符集名稱,如 "utf8mb4"

返回值:

  • 0:成功。

  • 非 0:失敗。

mysql_get_character_set_info

獲取當前連接的字符集信息,包括名字、說明、最大字節數等。

const MYSQL_CHARSET_INFO *mysql_get_character_set_info(MYSQL *mysql);

參數:

  • mysql:連接句柄。

返回值:

返回一個指向 MYSQL_CHARSET_INFO 的結構體指針,結構體包含如下字段:

struct charset_info_st {unsigned int  number;unsigned int  state;const char   *csname;     // 字符集名,如 "utf8mb4"const char   *name;       // 同上const char   *comment;    // 注釋,如 "UTF-8 Unicode"const char   *dir;        // 編碼文件路徑(客戶端庫)unsigned int  mbminlen;   // 最小字節數unsigned int  mbmaxlen;   // 最大字節數...
};

mysql_ping

測試當前連接是否有效;無效則嘗試自動重連(如果啟用自動重連)。

int mysql_ping(MYSQL *mysql);

參數:

  • mysql:連接句柄。

返回值:

  • 返回 0 表示連接有效

  • 返回非零表示連接斷開或檢測失敗

mysql_thread_id

獲取當前連接在服務器端的線程 ID,可用于日志記錄或跟蹤問題。

unsigned long mysql_thread_id(MYSQL *mysql);

參數:

  • mysql:連接句柄。

返回值:

  • 返回該連接在服務器上的線程 ID

mysql_get_client_info

獲取當前使用的 MySQL 客戶端庫的版本號,返回字符串形式。例如 "8.0.33"

const char *mysql_get_client_info(void);

mysql_get_server_info

獲取當前連接的 MySQL 服務器版本號(即遠程服務器端的版本),返回字符串。

const char *mysql_get_server_info(MYSQL *mysql);

示例:

#include <mysql/mysql.h>
#include <iostream>int main() {MYSQL *conn = mysql_init(NULL);if (!conn) {std::cerr << "mysql_init failed\n";return 1;}// 設置連接超時時間(3秒)int timeout = 3;mysql_options(conn, MYSQL_OPT_CONNECT_TIMEOUT, &timeout);// 設置連接前字符集(也可連接后使用 mysql_set_character_set 設置)const char *charset = "utf8mb4";mysql_options(conn, MYSQL_SET_CHARSET_NAME, charset);// 建立連接if (!mysql_real_connect(conn, "localhost", "root", "123456", "testdb", 3306, NULL, 0)) {std::cerr << "Connect failed: " << mysql_error(conn) << "\n";mysql_close(conn);return 1;}// 設置連接后字符集mysql_set_character_set(conn, "utf8mb4");// 打印連接信息std::cout << "Client version: " << mysql_get_client_info() << "\n";std::cout << "Server version: " << mysql_get_server_info(conn) << "\n";// 獲取字符集信息const MYSQL_CHARSET_INFO *cs = mysql_get_character_set_info(conn);std::cout << "Character set: " << cs->csname << ", comment: " << cs->comment << "\n";// 檢查連接是否有效if (mysql_ping(conn) == 0) {std::cout << "Ping successful. Connection is alive.\n";}// 打印線程 IDstd::cout << "Connection thread ID: " << mysql_thread_id(conn) << "\n";mysql_close(conn);return 0;
}

mysql_shutdown

此函數用于關閉 MySQL 服務器。必須具有管理員權限來執行此操作。

int mysql_shutdown(MYSQL *mysql, unsigned int shutdown_level, const char *shutdown_message);

參數:

  • mysql:已連接的 MYSQL 句柄。

  • shutdown_level:關閉級別:

    • SHUTDOWN_DEFAULT:常規關閉。

    • SHUTDOWN_WAIT:稍微延遲關閉(避免連接斷開)。

    • SHUTDOWN_GRACEFUL:平滑關閉(防止斷開已建立的連接)。

  • shutdown_message:可選的關閉消息(可為 NULL)。

返回值:

  • 成功:返回 0。

  • 失敗:返回非 0,調用 mysql_error() 獲取錯誤信息。

mysql_refresh

刷新 MySQL 服務器的緩存或狀態。常用于刷新日志、權限或其他內部狀態。

int mysql_refresh(MYSQL *mysql, unsigned int refresh_options);

參數說明:

  • mysql:已連接的 MYSQL 句柄。

  • refresh_options:刷新選項,組合為 OR:

    • REFRESH_GRANT:刷新權限。

    • REFRESH_LOG:刷新二進制日志。

    • REFRESH_TABLES:刷新表緩存。

    • REFRESH_HOSTS:刷新主機緩存。

    • REFRESH_STATUS:刷新狀態信息。

返回值:

  • 成功返回 0,失敗返回非 0。

mysql_kill

終止 MySQL 服務器中的線程。此操作需要管理員權限。

int mysql_kill(MYSQL *mysql, unsigned long thread_id);

參數說明:

  • mysql:已連接的 MYSQL 句柄。

  • thread_id:要終止的線程 ID。

返回值:

  • 成功:返回 0。

  • 失敗:返回非 0,調用 mysql_error() 獲取錯誤信息。

mysql_stat

獲取 MySQL 服務器的狀態信息。此函數返回一系列關于服務器運行狀態的統計數據。

char *mysql_stat(MYSQL *mysql);

參數:

  • mysql:已連接的 MYSQL 句柄。

返回值:

  • 返回服務器狀態信息的字符串。

  • 失敗時返回 NULL,調用 mysql_error() 獲取錯誤信息。

示例:

#include <mysql/mysql.h>
#include <cstdio>
#include <cstring>int main() {MYSQL *conn = mysql_init(NULL);if (!mysql_real_connect(conn, "localhost", "root", "password", "test_db", 0, NULL, 0)) {printf("Connection failed: %s\n", mysql_error(conn));return 1;}// 獲取服務器狀態char *status = mysql_stat(conn);if (status) {printf("Server Status: %s\n", status);} else {printf("Error retrieving server status: %s\n", mysql_error(conn));}// 刷新服務器(刷新權限、日志等)if (mysql_refresh(conn, REFRESH_GRANT | REFRESH_LOG)) {printf("Error refreshing server: %s\n", mysql_error(conn));} else {printf("Server refreshed successfully.\n");}// 假設要終止線程 ID 為 5if (mysql_kill(conn, 5)) {printf("Error killing thread: %s\n", mysql_error(conn));} else {printf("Thread killed successfully.\n");}// 關閉服務器if (mysql_shutdown(conn, SHUTDOWN_DEFAULT, "Shutting down server")) {printf("Error shutting down server: %s\n", mysql_error(conn));} else {printf("Server shut down successfully.\n");}mysql_close(conn);return 0;
}

2. 執行 SQL(直接執行)

mysql_query

用于向數據庫發送一條以 C 字符串形式的 SQL 查詢。適用于不包含二進制數據的簡單 SQL 命令(如 SELECTINSERTUPDATE 等)。

int mysql_query(MYSQL *mysql, const char *stmt_str);

參數:

  • mysql:指向已初始化并連接成功的 MYSQL 連接句柄。

  • stmt_str:SQL 查詢語句,以 C 字符串形式提供。

返回值:

  • 成功:返回 0

  • 失敗:返回非零,可通過 mysql_error() 獲取錯誤信息。

mysql_real_query

mysql_query 類似,但可以處理二進制數據(包括內嵌的空字符 \0),適用于更復雜的 SQL 語句。

int mysql_real_query(MYSQL *mysql, const char *stmt_str, unsigned long length);

參數:

  • mysql:數據庫連接句柄。

  • stmt_str:指向 SQL 查詢語句的指針。

  • length:語句的字節長度(不一定是 strlen(stmt_str),尤其當語句中含有 \0 時)。

返回值:

  • 成功:返回 0

  • 失敗:返回非零,可用 mysql_error() 獲取錯誤信息。

mysql_escape_string

對字符串進行轉義,防止 SQL 注入攻擊。適用于未連接數據庫的簡單轉義需求

為什么需要"轉義字符串"?

當拼接 SQL 語句時,如果直接將用戶輸入的數據寫入 SQL 字符串中,就可能導致 SQL 注入攻擊

示例:

const char* username = "O'Reilly";
char query[256];
sprintf(query, "INSERT INTO users(name) VALUES('%s')", username);

?拼接結果是:

INSERT INTO users(name) VALUES('O'Reilly')

由于名字中含有 ',SQL 會認為 'O' 是一個字符串,而 Reilly' 就變成了非法語法,這會導致 SQL 報錯,甚至黑客可以通過精心構造的字符串攻擊數據庫。

解決辦法:用 轉義函數 處理字符串mysql_escape_string

這個函數的作用就是將輸入字符串中的特殊字符(比如 ', ", \, NULL 字節等)轉義成安全的形式,以防止拼接 SQL 時出錯或被攻擊。

?? 注意:這個函數不依賴數據庫連接,只進行簡單的 ASCII 級別轉義,不考慮字符集編碼問題,所以只能在最簡單的場景中使用。

函數原型:

unsigned long mysql_escape_string(char *to, const char *from, unsigned long length);

參數:

  • to:目標緩沖區(用于保存轉義后的字符串)。

  • from:原始字符串。

  • length:原始字符串長度。

返回值:

  • 返回寫入 to 的字節數(不包括終止符 \0)。

mysql_real_escape_string

mysql_escape_string 類似,但使用連接信息(如字符集)進行轉義,它需要一個已經建立連接的 MYSQL * 參數。更推薦使用

unsigned long mysql_real_escape_string(MYSQL *mysql,char *to,const char *from,unsigned long length);

參數:

  • mysql:數據庫連接句柄(用于獲取字符集信息)。

  • to:目標緩沖區。

  • from:原始字符串。

  • length:原始字符串長度。

返回值:

  • 返回寫入 to 的字節數。

示例:

#include <mysql/mysql.h>
#include <stdio.h>
#include <string.h>int main() {MYSQL *conn = mysql_init(NULL);if (!mysql_real_connect(conn, "localhost", "root", "123456", "testdb", 0, NULL, 0)) {fprintf(stderr, "Connection failed: %s\n", mysql_error(conn));return 1;}// 用戶輸入需要轉義const char *user_input = "O'Reilly";char escaped[256];mysql_real_escape_string(conn, escaped, user_input, strlen(user_input));// 拼接 SQL 語句char query[512];snprintf(query, sizeof(query), "INSERT INTO users(name) VALUES('%s')", escaped);// 使用 mysql_real_query 執行語句if (mysql_real_query(conn, query, strlen(query))) {fprintf(stderr, "Query failed: %s\n", mysql_error(conn));} else {printf("Insert successful.\n");}mysql_close(conn);return 0;
}

3. 結果集處理(MYSQL_RES / MYSQL_ROW)

第一組:結果集的獲取與釋放

mysql_store_result

從服務器讀取完整結果集并緩存在客戶端內存中。

注意:必須先執行過一條會返回結果的 SQL 語句,比如 SELECT,然后才能調用 mysql_store_result() 來獲取“那條語句”的結果。

MYSQL_RES *mysql_store_result(MYSQL *mysql);

參數:

  • mysql:已連接的 MySQL 句柄。

返回值

  • 成功:返回 MYSQL_RES * 指針。

  • 無結果或失敗:返回 NULL。用 mysql_errno() 區分錯誤或無結果。

使用流程

mysql_query(conn, "SELECT id, name FROM users");  // 1. 先執行 SQL 查詢
MYSQL_RES* res = mysql_store_result(conn);       // 2. 再獲取結果集

mysql_use_result

初始化結果集,但不緩存整個結果集,適用于大結果集,節省內存,按行讀取。

MYSQL_RES *mysql_use_result(MYSQL *mysql);

?參數:

  • mysql:已經連接成功的 MYSQL 對象指針。

返回值:

  • 成功:返回指向 MYSQL_RES 的指針。

  • 失敗或無結果:返回 NULL,可以用 mysql_errno() 判斷原因。

注意事項:使用完后必須使用 mysql_free_result() 釋放,否則可能導致連接阻塞。

mysql_use_result()mysql_store_result() 的最大區別是——它不會一次性從服務器獲取并緩存整個結果集,而是每次調用 mysql_fetch_row() 時,從服務器取一行。

也就是說:

  • t不緩存全部行 → 節省客戶端內存。

  • 不能隨機訪問 → 不支持 mysql_data_seek()mysql_row_seek()

  • ?調用期間不能執行新的 SQL 查詢 → 因為結果還“留”在服務器端。

#include <mysql/mysql.h>
#include <iostream>int main() {.........// 執行查詢語句if (mysql_query(conn, "SELECT id, name FROM users")) {std::cerr << "mysql_query failed: " << mysql_error(conn) << "\n";mysql_close(conn);return 1;}// 使用 mysql_use_result 獲取結果(逐行獲取,節省內存)MYSQL_RES *res = mysql_use_result(conn);if (!res) {std::cerr << "mysql_use_result failed: " << mysql_error(conn) << "\n";mysql_close(conn);return 1;}// 獲取列數unsigned int num_fields = mysql_num_fields(res);// 遍歷結果集MYSQL_ROW row;while ((row = mysql_fetch_row(res))) {for (unsigned int i = 0; i < num_fields; ++i) {std::cout << (row[i] ? row[i] : "NULL") << "\t";}std::cout << "\n";}// 清理mysql_free_result(res);return 0;
}

mysql_free_result

釋放由 mysql_store_result()mysql_use_result() 獲取的結果集,避免內存泄漏。

void mysql_free_result(MYSQL_RES *result);

參數

  • result:指向 MYSQL_RES 的結果集指針。

第二組:逐行讀取數據

mysql_fetch_row

從結果集中提取下一行數據。

MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);

參數

  • result:由 mysql_store_result()mysql_use_result() 返回的結果集。

返回值

  • 成功:返回類型為 MYSQL_ROW(實質為 char **)的指針,表示一行數據。

  • 結束或無數據:返回 NULL

mysql_fetch_lengths

獲取當前行中每一列的數據長度(以字節為單位)。

unsigned long *mysql_fetch_lengths(MYSQL_RES *result);

參數

  • result:當前結果集,且必須在調用了 mysql_fetch_row() 之后調用本函數。

返回值

  • 成功:返回一個 unsigned long 類型的數組,每個元素表示當前行對應列的長度。

  • 失敗:返回 NULL

示例:

const char* query = "SELECT id, title, artist FROM songs";
if (mysql_query(conn, query)) {std::cerr << "Query failed: " << mysql_error(conn) << "\n";mysql_close(conn);return 1;
}MYSQL_RES *res = mysql_store_result(conn);
if (!res) {std::cerr << "mysql_store_result failed: " << mysql_error(conn) << "\n";mysql_close(conn);return 1;
}MYSQL_ROW row;while ((row = mysql_fetch_row(res))) {unsigned long *lengths = mysql_fetch_lengths(res);......
}

第三組:字段和元數據

mysql_num_rows

返回結果集的總行數。只適用于 mysql_store_result

參數

  • res:結果集指針。

返回值

  • 返回一個 my_ulonglong 類型的整數,表示結果集中的行數。

mysql_num_fields

返回結果集中字段(列)的數量。

unsigned int mysql_num_fields(MYSQL_RES *res);

參數

  • res:結果集指針。

返回值

  • 字段總數(列數)。

mysql_fetch_field

逐個提取字段的結構體信息,如字段名、類型、長度等。

MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result);

參數

  • result:結果集指針。

返回值

  • 成功:返回 MYSQL_FIELD*

  • 所有字段遍歷完畢:返回 NULL

mysql_fetch_fields

一次性返回所有字段信息的數組。

MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *res);

參數

  • res:結果集指針。

返回值

  • 成功:返回字段數組首地址(MYSQL_FIELD*)。

  • 失敗:返回 NULL

mysql_fetch_field_direct

根據索引直接獲取字段信息。

MYSQL_FIELD *mysql_fetch_field_direct(MYSQL_RES *res, unsigned int fieldnr);

參數

  • res:結果集指針。

  • fieldnr:字段索引(從 0 開始)。

返回值

  • 返回對應索引位置的字段信息指針。

mysql_field_seek

設置字段遍歷的偏移量,下一次 mysql_fetch_field() 會從該偏移開始。

MYSQL_FIELD_OFFSET mysql_field_seek(MYSQL_RES *res, MYSQL_FIELD_OFFSET offset);

參數

  • res:結果集指針。

  • offset:字段偏移值(可由 mysql_field_tell() 獲取)。

返回值

  • 返回設置前的位置(類型為 MYSQL_FIELD_OFFSET)。

mysql_field_tell

獲取當前字段指針的位置,可用于后續調用 mysql_field_seek() 返回到當前位置。

MYSQL_FIELD_OFFSET mysql_field_tell(MYSQL_RES *res);

參數

  • res:結果集指針。

返回值

  • 返回當前字段位置偏移量。

示例:

| id | title     | artist      |
| -- | --------- | ----------- |
| 1  | Yesterday | The Beatles |
| 2  | Hello     | Adele       |
| 3  | Imagine   | John Lennon |
#include <mysql/mysql.h>
#include <iostream>
#include <cstdlib>int main() {MYSQL *conn = mysql_init(nullptr);if (!conn) {std::cerr << "mysql_init failed\n";return 1;}// 建立連接if (!mysql_real_connect(conn, "localhost", "root", "123456", "test_db", 0, nullptr, 0)) {std::cerr << "Connection failed: " << mysql_error(conn) << "\n";return 1;}// 查詢語句const char* query = "SELECT id, title, artist FROM songs";if (mysql_query(conn, query)) {std::cerr << "Query failed: " << mysql_error(conn) << "\n";mysql_close(conn);return 1;}// 結果集MYSQL_RES *res = mysql_store_result(conn);if (!res) {std::cerr << "mysql_store_result failed: " << mysql_error(conn) << "\n";mysql_close(conn);return 1;}// 1. 獲取總行數my_ulonglong row_count = mysql_num_rows(res);std::cout << "總行數: " << row_count << "\n";  // 示例輸出: 總行數: 3// 2. 獲取字段總數unsigned int field_count = mysql_num_fields(res);std::cout << "字段數: " << field_count << "\n";  // 示例輸出: 字段數: 3// 3. 使用 mysql_fetch_fields 獲取所有字段信息MYSQL_FIELD *fields = mysql_fetch_fields(res);// 4. 使用 mysql_field_seek 和 mysql_fetch_field 重置字段位置并逐個讀取MYSQL_FIELD_OFFSET offset = mysql_field_seek(res, 0);  // 重置位置MYSQL_FIELD *field;while ((field = mysql_fetch_field(res))) {......}// 5. 使用 mysql_field_tell 獲取當前位置(已走到結尾)MYSQL_FIELD_OFFSET current_pos = mysql_field_tell(res);std::cout << "\n當前字段偏移位置 = " << current_pos << "\n";  // 示例輸出: 當前字段偏移位置 = 3// 6. 使用 mysql_fetch_field_direct 直接訪問字段信息std::cout << "\n使用 fetch_field_direct:\n";for (unsigned int i = 0; i < field_count; ++i) {field = mysql_fetch_field_direct(res, i);std::cout << "字段[" << i << "]: 名稱 = " << field->name << ", 類型 = " << field->type << "\n";}mysql_free_result(res);mysql_close(conn);return 0;
}

4.預處理語句(MYSQL_STMT)

預處理語句:

預處理語句是數據庫提供的一種 高效、安全的執行 SQL 語句 的機制,它將 SQL 語句的結構和數據分開處理。

預處理語句先告訴數據庫:“我要做一件什么事(SQL結構)”,然后再告訴它:“我要用哪些數據來做這件事”。也就是說,預處理語句把一個完整的 SQL 操作分成 兩步走

第一步:定義你要做的事情(SQL語句結構)
第二步:告訴它你要用哪些數據(填入參數)

示例:

?假設有一條插入語句:

INSERT INTO users (name, age) VALUES ('Alice', 25);

在 C /c++代碼里用字符串拼接是這樣寫的:

char sql[100];
sprintf(sql, "INSERT INTO users (name, age) VALUES ('%s', %d);", name, age);
mysql_query(conn, sql);

問題:

  • 這容易出錯(比如字符串中有 ' 或特殊字符)

  • 還有嚴重的 SQL 注入風險!

改用預處理語句后把 SQL 寫成這樣:

INSERT INTO users (name, age) VALUES (?, ?);
  • ? 是占位符,代表后面你再填入的參數。

  • SQL 結構不變,數據單獨綁定,不會被解釋為語句的一部分。

  • 執行流程由你控制,像“先建模,再灌數據”。

預處理語句主要優勢:

①防止 SQL 注入攻擊(安全性高)

使用預處理語句時,SQL 語句中使用 ? 占位符 來代表參數,不再通過字符串拼接直接構造 SQL。數據(參數)與語句分離,數據庫會將參數 按值處理,不會被解釋為 SQL 指令。

不安全(傳統拼接):

char sql[200];
sprintf(sql, "SELECT * FROM users WHERE username = '%s'", user_input);  // 易受注入攻擊SQL 注入是指:攻擊者把惡意的 SQL 代碼,偽裝成用戶輸入,拼接進原本的 SQL 語句中,從而控制數據庫行為,甚至獲取敏感數據、刪除表等。
示例:
用戶輸入的是:user_input = "Alice";
拼接后的 SQL 是:SELECT * FROM users WHERE username = 'Alice';
這個 SQL 沒有問題,會查找 username = 'Alice' 的用戶。但如果攻擊者輸入的是:user_input = "' OR '1'='1";
拼接后的 SQL 就變成了:SELECT * FROM users WHERE username = '' OR '1'='1';
這意味著:只要條件 1=1 成立(它永遠成立),就會返回數據庫中所有用戶信息!所以 SQL 注入本質是:
利用你把用戶輸入當作 SQL 的一部分來拼接字符串,偽造出攻擊性的 SQL。

安全(預處理):

SELECT * FROM users WHERE username = ?

然后通過 mysql_stmt_bind_param 將參數單獨傳入,數據庫會把參數值當作純文本。

②性能更高(尤其適合重復執行)

預處理語句將 SQL 的 解析、語法檢查和優化 階段只做一次。你可以多次 綁定不同參數 進行執行,數據庫會重用之前編譯好的語句結構。

適用場景:

  • 同一條 SQL 要反復執行,例如插入大量數據(批量 INSERT)。

  • 每次數據不同但 SQL 結構不變。

第一組:初始化與準備

mysql_stmt_init

初始化一個預處理語句句柄。

MYSQL_STMT *mysql_stmt_init(MYSQL *mysql);

參數

  • mysql:已連接的 MYSQL 對象指針。

返回值

  • 成功:返回新分配的 MYSQL_STMT 指針。

  • 失敗:返回 NULL

mysql_stmt_prepare

為預處理語句對象編譯 SQL 語句。

int mysql_stmt_prepare(MYSQL_STMT *stmt, const char *query, unsigned long length);

參數

  • stmt:預處理語句對象。

  • query:SQL 查詢語句字符串(使用 ? 占位符)。

  • length:SQL 字符串的長度(以字節為單位)。

返回值

  • 成功:返回 0。

  • 失敗:返回非零,可使用 mysql_stmt_errno() 獲取錯誤碼。

示例:

MYSQL_STMT* stmt = mysql_stmt_init(conn);
const char* sql = "INSERT INFO songs (id, title, artist) VALUES (?, ?, ?)";
if (mysql_stmt_prepare(stmt, sql, strlen(sql))) {std::cout << "some error" << mysql_stmt_error(stmt));
}

第二組:參數綁定與執行

mysql_stmt_bind_param

將數據綁定到預處理語句的參數中。

int mysql_stmt_bind_param(MYSQL_STMT *stmt, MYSQL_BIND *bind);

參數

  • stmt:預處理語句對象。

  • bindMYSQL_BIND 數組,每個元素綁定一個參數。

返回值

  • 成功:返回 0。

  • 失敗:返回非零。

mysql_stmt_execute

執行已準備好的語句。

int mysql_stmt_execute(MYSQL_STMT *stmt);

參數

  • stmt:已準備并綁定參數的語句句柄。

返回值

  • 成功:返回 0。

  • 失敗:返回非零。

示例:

int id = 4;
char title[100] = "acdscadscas";
char artist[100] = "acdsdcd";MYSQL_BIND bind[3];
memset(bind, 0, sizeof(bind));bind[0].buffer_type = MYSQL_TYPE_LONG;
bind[0].buffer = &id;bind[1].buffer_type = MYSQL_TYPE_STRING;
bind[1].buffer = title;
bind[1].buffer_length = sizeof(title);bind[2].buffer_type = MYSQL_TYPE_STRING;
bind[2].buffer = artist;
bind[2].buffer_length = sizeof(artist);if (mysql_stmt_bind_param(stmt, bind) != 0 ||mysql_stmt_execute(stmt) != 0) {std::cout << "some error" << mysql_stmt_error(stmt));
}

第三組:結果綁定與提取

mysql_stmt_bind_result

將變量綁定到語句的輸出結果列。?

int mysql_stmt_bind_result(MYSQL_STMT *stmt, MYSQL_BIND *bind);

參數

  • stmt:執行了 SELECT 的語句句柄。

  • bind:用于接收結果的變量數組。

返回值

  • 成功:返回 0。

  • 失敗:返回非零。

mysql_stmt_fetch

逐行獲取結果。

int mysql_stmt_fetch(MYSQL_STMT *stmt);

參數

  • stmt:結果已綁定的語句句柄。

返回值

  • 成功:返回 0。

  • 沒有更多行:返回 MYSQL_NO_DATA

  • 錯誤:返回 1

示例:

MYSQL_STMT *select_stmt = mysql_stmt_init(conn);
const char *sql = "SELECT id, title FROM songs WHERE artist = ?";
mysql_stmt_prepare(select_stmt, sql, strlen(sql));char artist_filter[] = "The Beatles";
MYSQL_BIND param[1];
memset(param, 0, sizeof(param));
param[0].buffer_type = MYSQL_TYPE_STRING;
param[0].buffer = artist_filter;
param[0].buffer_length = strlen(artist_filter);mysql_stmt_bind_param(select_stmt, param);
mysql_stmt_execute(select_stmt);int id;
char title[100];
MYSQL_BIND result[2];
memset(result, 0, sizeof(result));
result[0].buffer_type = MYSQL_TYPE_LONG;
result[0].buffer = &id;
result[1].buffer_type = MYSQL_TYPE_STRING;
result[1].buffer = title;
result[1].buffer_length = sizeof(title);mysql_stmt_bind_result(select_stmt, result);while (mysql_stmt_fetch(select_stmt) == 0) {printf("id: %d, title: %s\n", id, title);
}

第四組:結果緩存與元數據相關函數

mysql_stmt_store_result

將結果集從服務器讀取并緩存到客戶端,適用于隨機訪問或多次訪問結果的場景。

int mysql_stmt_store_result(MYSQL_STMT *stmt);

參數

  • stmt:執行了 SELECT 的語句句柄。

返回值

  • 成功:返回 0

  • 失敗:返回非零,使用 mysql_stmt_errno() 獲取錯誤碼。

注意:

  • 如果你需要使用 mysql_stmt_num_rows() 或者 mysql_stmt_data_seek(),必須先調用本函數。

  • 類似于 mysql_store_result(),但用于預處理語句。

mysql_stmt_result_metadata

獲取結果集的字段元信息(例如列名、類型、長度等)。

MYSQL_RES *mysql_stmt_result_metadata(MYSQL_STMT *stmt);

參數

  • stmt:準備并執行了 SELECT 的語句句柄。

返回值

  • 成功:返回 MYSQL_RES *,可通過 mysql_fetch_field()mysql_num_fields() 等分析字段結構。

  • 失敗或無字段結果:返回 NULL

用途

  • 當你想動態綁定結果時(不知道返回字段數),可先調用本函數來獲知字段信息。

mysql_stmt_param_metadata

獲取語句的參數信息(占位符參數的數量、類型等)。

MYSQL_RES *mysql_stmt_param_metadata(MYSQL_STMT *stmt);

參數

  • stmt:已經調用 mysql_stmt_prepare() 的語句句柄。

返回值

  • 成功:返回 MYSQL_RES *,可用于查看參數數量和類型。

  • 無參數或失敗:返回 NULL

示例:

mysql_stmt_prepare(stmt, sql, strlen(sql));// 綁定輸入參數
char artist[] = "The Beatles";
MYSQL_BIND param[1];
memset(param, 0, sizeof(param));
param[0].buffer_type = MYSQL_TYPE_STRING;
param[0].buffer = artist;
param[0].buffer_length = strlen(artist);
mysql_stmt_bind_param(stmt, param);
mysql_stmt_execute(stmt);// 獲取元數據(字段名、類型等)
MYSQL_RES *meta_result = mysql_stmt_result_metadata(stmt);// 獲取結果集中字段數量
unsigned int field_count = mysql_num_fields(meta_result);
// 假設 SQL 為:SELECT id, title FROM songs WHERE artist = ?
// 那么字段數量為 2(即 id 和 title)
/*field_count = 2
*/// 獲取字段數組,包含每個字段的元信息(字段名、類型等)
MYSQL_FIELD *fields = mysql_fetch_fields(meta_result);
/*fields[0].name = "id"fields[0].type = MYSQL_TYPE_LONG (對應數字類型 INT)fields[1].name = "title"fields[1].type = MYSQL_TYPE_STRING 或 MYSQL_TYPE_VAR_STRING(VARCHAR 類型)
*/// 打印字段元信息
for (unsigned int i = 0; i < field_count; i++) {printf("Column %d: name = %s, type = %d\n", i, fields[i].name, fields[i].type);
}/*上面循環的實際輸出將為:Column 0: name = id, type = 3Column 1: name = title, type = 253注:type = 3   表示 MYSQL_TYPE_LONG(整數)type = 253 表示 MYSQL_TYPE_VAR_STRING(VARCHAR)
*/// 獲取結果并緩存(必須在 fetch 前調用,允許隨機訪問結果)
mysql_stmt_store_result(stmt);

mysql_stmt_num_rows

獲取結果集中總行數(在 mysql_stmt_store_result() 之后使用)

my_ulonglong mysql_stmt_num_rows(MYSQL_STMT *stmt);

參數

  • stmt:已執行并緩存結果的語句句柄。

返回值

  • 成功:返回結果集中的總行數。

  • 失敗:返回 0。

示例:

mysql_stmt_store_result(stmt);
my_ulonglong row_count = mysql_stmt_num_rows(stmt);

mysql_stmt_data_seek

移動結果集的內部行指針,用于“跳轉”讀取特定行(僅適用于 store_result() 緩存模式)

void mysql_stmt_data_seek(MYSQL_STMT *stmt, my_ulonglong offset);

參數

  • stmt:語句句柄

  • offset:目標行索引(從 0 開始)

MYSQL_STMT *stmt = mysql_stmt_init(conn);
const char *sql = "SELECT id, title FROM songs";
mysql_stmt_prepare(stmt, sql, strlen(sql));
mysql_stmt_execute(stmt);// 綁定結果
int id;
char title[100];
MYSQL_BIND result[2];
memset(result, 0, sizeof(result));
result[0].buffer_type = MYSQL_TYPE_LONG;
result[0].buffer = &id;
result[1].buffer_type = MYSQL_TYPE_STRING;
result[1].buffer = title;
result[1].buffer_length = sizeof(title);
mysql_stmt_bind_result(stmt, result);// 緩存結果(這是使用 data_seek 的前提)
mysql_stmt_store_result(stmt);// 第一次 fetch 讀取結果集中的第一行
mysql_stmt_fetch(stmt);
printf("[第一次] id: %d, title: %s\n", id, title);  
// 輸出:[第一次] id: 1, title: Yesterdaymysql_stmt_fetch(stmt); 讀取結果集中的第二行
printf("[第二次] id: %d, title: %s\n", id, title);  
// 輸出:[第二次] id: 2, title: Hello// 使用 data_seek 跳回第 0 行(第一行)
mysql_stmt_data_seek(stmt, 0);// 再 fetch 一次,應該是第一行
mysql_stmt_fetch(stmt);
printf("[跳回后] id: %d, title: %s\n", id, title);  
// 輸出:[跳回后] id: 1, title: Yesterday

mysql_stmt_free_result

釋放語句對象中存儲的結果集內存,釋放后不能再調用 fetch

int mysql_stmt_free_result(MYSQL_STMT *stmt);

參數

  • stmt:語句句柄

返回值

  • 成功:返回 0

  • 失敗:返回非零

mysql_stmt_free_result(stmt);調用時機:在完成數據讀取后及時釋放內存。

第五組:預處理語句的輔助與控制函數

mysql_stmt_attr_set

設置語句句柄的屬性,例如設置最大緩沖行數(可控制 mysql_stmt_store_result 的行為)。

int mysql_stmt_attr_set(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, const void *attr);

?參數:

  • stmt:預處理語句句柄。

  • attr_type:屬性類型,常用值包括:

    • STMT_ATTR_UPDATE_MAX_LENGTH:是否更新字段的最大長度信息。

    • STMT_ATTR_CURSOR_TYPE:設置游標類型(如 CURSOR_TYPE_READ_ONLY)。

    • STMT_ATTR_PREFETCH_ROWS:設置預取行數(優化 fetch 行為)。

  • attr:指向屬性值的指針。

返回值

  • 成功:0

  • 失敗:非零

mysql_stmt_attr_get

獲取語句當前某個屬性的值。

int mysql_stmt_attr_get(MYSQL_STMT *stmt, enum enum_stmt_attr_type attr_type, void *attr);

參數
attr_set 類似,只是 attr 是用來接收屬性值的指針。

返回值
成功返回 0,失敗返回非零。

示例:

設置并獲取 STMT_ATTR_UPDATE_MAX_LENGTH 屬性

這個屬性的含義是:

是否在 mysql_stmt_store_result() 后自動更新字段的最大長度(比如字符串字段的最大長度)
設置為 1 表示“更新字段最大長度信息”,設置為 0 表示“不更新”。

// 設置屬性:開啟字段最大長度自動更新
my_bool set_val = 1;
if (mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &set_val) != 0) {fprintf(stderr, "Failed to set stmt attribute\n");
}// 獲取屬性:驗證設置是否生效
my_bool get_val = 0;
if (mysql_stmt_attr_get(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &get_val) != 0) {fprintf(stderr, "Failed to get stmt attribute\n");
} else {printf("STMT_ATTR_UPDATE_MAX_LENGTH = %d\n", get_val);  // 輸出應為 1,表示設置成功
}

mysql_stmt_errno

獲取最近一條預處理語句操作的錯誤碼。

unsigned int mysql_stmt_errno(MYSQL_STMT *stmt);

mysql_stmt_error

獲取最近一條語句操作的錯誤信息(字符串形式)。

const char *mysql_stmt_error(MYSQL_STMT *stmt);

mysql_stmt_reset

重置語句(清除綁定的參數與結果、狀態等,但不釋放語句)。

int mysql_stmt_reset(MYSQL_STMT *stmt);

mysql_stmt_close

關閉語句并釋放預處理語句句柄的所有資源。

int mysql_stmt_close(MYSQL_STMT *stmt);

示例:

MYSQL_STMT *stmt = mysql_stmt_init(conn);
const char *sql = "SELECT title FROM songs";
if (mysql_stmt_prepare(stmt, sql, strlen(sql))) {fprintf(stderr, "Prepare failed: %s\n", mysql_stmt_error(stmt));return;
}
........
// 清理
mysql_free_result(meta);
mysql_stmt_close(stmt);

5. 事務控制

事務是什么?

事務是一組操作的集合,事務會把所有操作作為一個整體一起向系統提交或撤銷操作請求,即這些操作要么同時成功,要么同時失敗。

一句話:事務就是一組必須“要么全做完,要么一個也不做”的數據庫操作。

比如:銀行轉賬操作 —— 張三轉賬給李四 1000 元,不能出現張三的錢扣了但李四沒收到的情況。

示例:

-- 1. 查詢張三賬戶余額
select * from account where name = '張三';
-- 2. 將張三賬戶余額-1000
update account set money = money - 1000 where name = '張三';
-- 此語句出錯后張三錢減少但是李四錢沒有增加
模擬sql語句錯誤
-- 3. 將李四賬戶余額+1000
update account set money = money + 1000 where name = '李四';這時如果沒有事務:

此時張三的錢就被扣了,李四的錢卻沒有增加,錢“憑空消失”,數據錯誤了!

所以必須讓這步操作打包成一組事務,要么一起成功、要么一起失敗回滾。

mysql_autocommit

這個函數是事務控制的開關,控制是否開啟“自動提交模式”。

  • 默認情況下,MySQL 每執行一條 INSERTUPDATEDELETE 就會立即 COMMIT,這叫“自動提交”。

  • 如果你希望在多條 SQL 執行后統一提交或撤銷(比如錢轉了一半不能讓數據庫寫進去),就需要關閉自動提交,手動控制事務。

int mysql_autocommit(MYSQL *mysql, my_bool mode);

參數:

  • mysql:連接句柄。

  • mode

    • 1(默認):開啟自動提交模式(每條語句執行后自動提交)。

    • 0:關閉自動提交,意味著你要手動用 mysql_commit()mysql_rollback() 控制事務提交。

返回值:
  • 成功返回 0,失敗返回非 0。

mysql_autocommit(conn, 0); // 相當于 START TRANSACTION;

mysql_commit

這個函數提交事務,將你執行的所有數據更改操作真正“寫入數據庫”。

  • 如果你執行了多條修改語句(例如插入了幾條訂單信息),但還沒調用 mysql_commit(),那么這些修改還沒有真正寫入磁盤(處于事務緩存中)。

  • 只有調用 mysql_commit(),事務才算真正結束,數據才會變為持久化。

int mysql_commit(MYSQL *mysql);

返回值:

  • 成功返回 0,失敗返回非 0。

注意:

在使用事務時,如果你還沒有調用 mysql_commit() 提交事務,此時數據庫連接突然斷掉(比如網絡斷了、程序崩潰了、數據庫宕機了),那么:當前正在執行的事務會被自動取消,數據庫會幫你回滾!

示例:

假設執行了一系列數據庫操作,比如:

START TRANSACTION;
UPDATE users SET balance = balance - 100 WHERE id = 1;
UPDATE users SET balance = balance + 100 WHERE id = 2;

這時候你還沒調用 COMMIT; —— 也就是說事務還在進行中。

但突然:

  • 程序崩潰了,

  • 數據庫斷網了,

  • 或者數據庫服務掛了,

那么:這兩個 UPDATE 操作 都不會被保存MySQL 會自動回滾這些未提交的修改

mysql_rollback

這個函數是 commit() 的“反操作”:撤銷當前事務中的所有修改。如果你在執行多條語句后發現某一步出錯,就可以調用它,防止錯誤寫入數據庫。

int mysql_rollback(MYSQL *mysql);

返回值:

  • 成功返回 0,失敗返回非 0。

示例:

// 訂單支付邏輯
mysql_autocommit(conn, 0);if (mysql_query(conn, "INSERT INTO orders ...") ||mysql_query(conn, "UPDATE users SET balance = balance - 100 ...")) {// 有一步失敗,撤銷所有操作mysql_rollback(conn);
} else {mysql_commit(conn); // 所有操作成功,確認寫入
}

mysql_more_results

這個函數用于判斷你是否還有下一個結果集可讀取,通常和 mysql_next_result() 搭配。

通常用于多語句查詢(multi-statement),比如:

SELECT * FROM table1; SELECT * FROM table2;

此時執行后會有兩個結果集,而不是一個。

bool mysql_more_results(MYSQL *mysql);
返回值:
  • true:還有下一個結果集。

  • false:所有結果集都已讀取完。

mysql_next_result

這個函數讓你進入下一個結果集。它配合 mysql_more_results() 一起用。

比如執行的是:

SELECT * FROM users; SELECT * FROM songs;

執行一次 mysql_store_result() 只能取到 users,想要取 songs 就需要用 mysql_next_result()

int mysql_next_result(MYSQL *mysql);

返回值:

  • 成功:返回 0,說明成功切換到下一個結果集。

  • 沒有更多結果:返回 -1

  • 錯誤:返回大于 0 的值。

mysql_autocommit(conn, 0);  // 關閉自動提交,開啟事務// 執行多條 SQL(多語句查詢)
const char *multi_sql = "INSERT INTO log(msg) VALUES('start'); SELECT * FROM songs;";
if (mysql_query(conn, multi_sql)) {fprintf(stderr, "執行失敗:%s\n", mysql_error(conn));mysql_rollback(conn);
} else {// 提交事務mysql_commit(conn);// 獲取第一結果(INSERT 無結果)MYSQL_RES *res = mysql_store_result(conn);if (res) mysql_free_result(res); // 忽略 INSERT 的結果集// 有更多結果?while (mysql_more_results(conn)) {if (mysql_next_result(conn) == 0) {res = mysql_store_result(conn);if (res) {MYSQL_ROW row;while ((row = mysql_fetch_row(res))) {printf("歌曲名:%s\n", row[1]);}mysql_free_result(res);}}}
}mysql_autocommit(conn, 1);  // 恢復自動提交模式

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

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

相關文章

Java EE(Spring+Spring MVC+MyBatis)從入門到精通企業級應用開發教程——1初識MyBatis框架

1、MyBatis工作原理 MyBatis操作數據庫流程分為8個步驟&#xff0c;具體介紹如下&#xff1a; &#xff08;1&#xff09;MyBatis讀取核心配置文件mybatis-config.xml mybatis-config.xml核心配置文件主要配置了MyBatis的運行環境等信息。 &#xff08;2&#xff09;加載映射…

【許可證】Open Source Licenses

長期更新 擴展&#xff1a;shield.io裝飾 開源許可證&#xff08;Open Source Licenses&#xff09;有很多種&#xff0c;每種都有不同的授權和限制&#xff0c;適用于不同目的。 默認的ISC&#x1f7f0;MIT License是否可商用是否要求開源衍生項目是否必須署名是否有專利授權…

ZooKeeper工作機制與應用場景

目錄 1.1、概述1.2、選舉機制1.2.1、選舉觸發條件1.2.2、選舉規則1.2.3、選舉過程詳解 1.3、數據同步機制1.3.1、正常同步1.3.2、宕機同步 1.4、客戶端常用命令1.5、應用場景1.5.1、配置管理1.5.2、命令服務1.5.3、分布式鎖服務1.5.4、集群管理1.5.5、分布式ID1.5.6、分布式協調…

前端面經-VUE3篇(四)--pinia篇-基本使用、store、state、getter、action、插件

一、基本使用 1、什么是 Pinia&#xff1f; Pinia 是 Vue.js 的官方狀態管理庫&#xff0c;是 Vuex 的“升級版”。它專為 Vue 3 和 Composition API 設計&#xff0c;用于管理多個組件之間共享的數據&#xff08;也叫“全局狀態”&#xff09;。 2、為什么需要狀態管理庫&a…

數據結構之圖的遍歷

圖的遍歷 圖的遍歷目的是訪問圖的每一個頂點恰好一次,&#xff0c;同時訪問圖中每條邊恰好一 次。 對于無向圖&#xff0c;常見的遍歷方式有深度優先遍歷&#xff08;Depth-First Search, DFS&#xff09; 和廣度優先遍歷&#xff08;Breadth-First Search, BFS&#xff09;。…

Ubuntu 第11章 網絡管理_常用的網絡配置命令

為了管理網絡&#xff0c;Linux提供了許多非常有用的網絡管理命令。利用這些命令&#xff0c;一方面可以有效地管理網絡&#xff0c;另一方面出現網絡故障時&#xff0c;可以快速進行診斷。本節將對Ubuntu提供的網絡管理命令進行介紹。 11.2.1 ifconfig命令 關于ifconfig命令&…

Qt解決自定義窗口樣式不生效問題

方法一&#xff1a; this->setAttribute(Qt::WA_StyledBackground, true); 方法二&#xff1a; 將類繼承QWidget 改成繼承 QFrame class MyWidget : public QFrame {} 方法三&#xff1a;重新實現QWidget的paintEvent函數時&#xff0c;使用QStylePainter繪制。 void p…

HNUST湖南科技大學-軟件測試期中復習考點(保命版)

使用說明&#xff1a;本復習考點僅用于及格保命。軟件測試和其他專業課不太一樣&#xff0c;記憶的太多了&#xff0c;只能說考試的時候&#xff0c;想到啥就寫啥&#xff0c;多寫一點&#xff01;多寫一點&#xff01;多寫一點&#xff01;&#xff08;重要事情說三遍&#xf…

ES6 知識點整理

一、變量聲明&#xff1a;var、let、const 的區別 作用域 var&#xff1a;函數作用域&#xff08;函數內有效&#xff09;。let/const&#xff1a;塊級作用域&#xff08;{} 內有效&#xff0c;如 if、for&#xff09;。 變量提升 var 會提升變量到作用域頂部&#xff08;值為…

分布式爬蟲去重:Python + Redis實現高效URL去重

1. 引言 在互聯網數據采集&#xff08;爬蟲&#xff09;過程中&#xff0c;URL去重是一個關鍵問題。如果不對URL進行去重&#xff0c;爬蟲可能會重復抓取相同頁面&#xff0c;導致資源浪費、數據冗余&#xff0c;甚至觸發目標網站的反爬機制。 對于單機爬蟲&#xff0c;可以使…

C# WPF 顏色拾取器

x:Name=Color Picker 語言:C# WPF 下載:https://download.csdn.net/download/polloo2012/90780640 主界面 顏色庫 關于我們 顏色拾取器是一種能夠幫助用戶獲取顏色信息,并進行顏色選擇、識別和調整的工具,以下將從其常見類型、使用場景及部分軟件工具這幾個維度展開介紹…

Git 使用的全流程以及SourceTree工具的使用操作和忽略文件的配置

1. 安裝 Git 要使用 Git&#xff0c;首先得在你的系統上安裝它。你可以按照不同操作系統的安裝指南來操作&#xff1a; Windows&#xff1a;訪問 Git 官方下載頁面&#xff0c;下載安裝程序并運行。 macOS&#xff1a;可以使用 Homebrew 來安裝&#xff0c;命令為 brew inst…

《深入理解Linux網絡》筆記

《深入理解Linux網絡》筆記 前言參考 前言 前段時間看了《深入理解Linux網絡》這本書&#xff0c;雖然有些地方有以代碼充篇幅的嫌疑&#xff0c;但總體來說還是值得一看的。在這里簡單記錄一下筆記&#xff0c;記錄下對網絡新的理解。 內核是如果接受網絡包的&#xff1f; 如…

數倉-可累計,半累加,不可累加指標,是什么,舉例說明及解決方案

目錄 1. 可累計指標定義&#xff1a;舉例&#xff1a;解決方案&#xff1a; 2. 半累加指標定義&#xff1a;舉例&#xff1a;解決方案&#xff1a; 3. 不可累加指標定義&#xff1a;舉例&#xff1a;解決方案&#xff1a; 4. 總結對比5. 實際場景中的注意事項 這是數據倉庫設計…

NestJS 的核心構建塊有哪些?請簡要描述它們的作用(例如,Modules, Controllers, Providers)

NestJS 核心構建塊解析&#xff08;Modules、Controllers、Providers&#xff09; NestJS 是一個基于 TypeScript 的漸進式 Node.js 框架&#xff0c;核心設計借鑒了 Angular 的模塊化思想。下面從實際開發角度解析它的三大核心構建塊&#xff0c;并附代碼示例和避坑指南。 一…

vue2 上傳pdf,拖拽蓋章,下載圖片

效果圖片&#xff1a; 不多廢話上代碼&#xff1a; <template><div class"pdf-stamp" onbeforecopyreturn false onselectdocument.selection.empty() ondragstartreturn false onselectstart return false ><div class"scroll-box" scro…

理性地傾聽與表達:檢索算法的語言學改進

論文標題 Rational Retrieval Acts: Leveraging Pragmatic Reasoning to Improve Sparse Retrieval 論文地址 https://arxiv.org/pdf/2505.03676 代碼地址 https://github.com/arthur-75/Rational-Retrieval-Acts 作者背景 巴黎薩克雷大學&#xff0c;索邦大學&#xff…

MySQL及線程關于鎖的面試題

目錄 1.了解過 MySQL 死鎖問題嗎&#xff1f; 2.什么是線程死鎖&#xff1f;死鎖相關面試題 2.1 什么是死鎖&#xff1a; 2.2 形成死鎖的四個必要條件是什么&#xff1f; 2.3 如何避免線程死鎖&#xff1f; 3. MySQL 怎么排查死鎖問題&#xff1f; 4.Java線上死鎖問題如…

【Reality Capture 】Reality Capture1.5中文版安裝教程(附安裝包下載)

文章目錄 一、Reality Capture1.5中文版安裝教程二、拷貝中文補丁三、Reality Capture1.5中文版下載地址一、Reality Capture1.5中文版安裝教程 1. Reality Capture v1.4.0漢化版安裝包下載并解壓 2. 運行EpicInstaller-15.17.1-4a91a118786f4c2aa3c0093b23f83863.msi 3. 更改…

SVG數據可視化設計(AI)完全工作流解讀|計育韜

AI 的 SVG 創作極限在哪里&#xff1f;絕不是那些初級的流程圖生成和粗糙的商業模型設計。以下是由我們 JZ Creative Studio 通過 Claude 和 Deepseek 開展的專業級 SVG Data Visualization 創作&#xff0c;應廣大讀者強烈要求&#xff0c;專程直播講授了一期 AI 工作流分享。…