- 一、初始化
- 參數
- 返回值
- 二、鏈接服務器
- 三、執行SQL語句
- 注意事項
- 四、獲取結果集
- 4.1mysql_affected_rows和mysql_num_rows
- 4.2mysql_store_result與mysql_free_result
- 注意事項
- 注意事項
- 整體的工作流程
- 4.3mysql_use_result()
- 4.4mysql_field_count()
- 五、關閉MySQL
- 使用和區別
- 六、錯誤處理
- mysql_errno()` 和 `mysql_error()
一、初始化
創建MYSQL* 對象,使用mysql_init函數
MYSQL * mysql;
mysql_init(mysql);
參數
mysql
:指向一個MYSQL
結構的指針。通常傳遞NULL
,系統將自動為您分配和初始化一個新的MYSQL
對象。
返回值
- 成功:返回一個指向
MYSQL
結構的指針。 - 失敗:返回
NULL
。
二、鏈接服務器
使用函數mysql_real_connect();
MYSQL *mysql_real_connect(MYSQL *mysql, // mysql_init() 函數的返回值const char *host, // mysql服務器的主機地址, 寫IP地址即可// localhost, null -> 代表本地連接const char *user, // 連接mysql服務器的用戶名, 默認: root const char *passwd, // 連接mysql服務器用戶對應的密碼, root用戶的密碼const char *db, // 要使用的數據庫的名字unsigned int port, // 連接的mysql服務器監聽的端口// 如果==0, 使用mysql的默認端口3306, !=0, 使用指定的這個端口const char *unix_socket,// 本地套接字, 通常在 Windows 上使用命名管道,而在 Unix/Linux 系統上使用 Unix 套接字。如果不使用這類連接方式,此參數應設為 NULL。unsigned long client_flag); //連接時使用的特定客戶端標志 通常指定為0
)
返回值:
- 成功:返回一個指向 MYSQL 結構的指針(通常是傳入的那個指針)。
- 失敗:返回 NULL,并且可以通過
mysql_error
函數來獲取錯誤信息。
三、執行SQL語句
// 執行一個sql語句, 添刪查改的sql語句都可以
int mysql_query(MYSQL *mysql, const char *query);
參數:- mysql: mysql_real_connect() 的返回值- query: 一個可以執行的sql語句, 結尾的位置不需要加 ;
返回值: - 如果查詢成功,返回0。如果是查詢, 結果集在mysql 對象中- 如果出現錯誤,返回非0值。
注意事項
- 資源管理:使用
mysql_query
后,如果查詢是 SELECT 類型的,你通常需要調用mysql_store_result
或mysql_use_result
來處理返回的數據。記得在不需要結果集時使用mysql_free_result
來釋放內存。- 錯誤處理:在生產環境中,每次調用
mysql_query
后都應檢查返回值,并適當處理錯誤。這樣可以避免程序在錯誤狀態下繼續執行,導致更復雜的問題。- 安全性:避免將未經驗證的用戶輸入直接用于 SQL 語句,以防止 SQL 注入攻擊。考慮使用預處理語句和參數化查詢來提高安全性。
這些基本的使用方式和注意事項可以幫助你有效地使用
mysql_query
來執行數據庫操作。
值得注意的是在 MySQL 中,SQL 語句的關鍵字(如 SELECT
, INSERT
, UPDATE
, DELETE
等)通常是不區分大小寫的,這意味著 “select” 和 “SELECT” 在 MySQL 解釋器看來是相同的。然而,數據庫名稱、表名、列名的大小寫敏感性則取決于操作系統的文件系統和 MySQL 的配置。在 Unix、Linux 系統中,它們默認是大小寫敏感的,而在 Windows 系統中默認是不敏感的。
mysql_query
實質上是在客戶端和 MySQL 服務器之間進行網絡通信的一個接口。在使用 TCP/IP 協議的情況下,客戶端通過網絡向服務器發送請求,并接收服務器的響應。這個過程涉及到網絡數據的發送和接收,是基于客戶端-服務器模型的典型應用。
要注意的是標準 SQL 查詢:如果你的查詢是簡單的文本,不包含二進制數據,且不需要在 SQL 語句中嵌入 null 字符,使用 mysql_query
就足夠了。
而當數據中有二進制數據就需要使用mysql_real_query
int mysql_real_query(MYSQL *mysql, const char *query, unsigned long length);
- 靈活性:可以執行包含 null 字符的查詢,因為它要求用戶明確提供查詢的長度。
- 手動指定長度:用戶必須指定查詢字符串的長度,這允許函數處理二進制數據或包含 null 字符的數據。
- 適用場景:非常適合執行包含 BLOB 類型數據的 SQL 語句。
四、獲取結果集
4.1mysql_affected_rows和mysql_num_rows
uint64_t mysql_affected_rows(MYSQL *mysql)
mysql_affected_rows() 可能是 在使用 mysql_real_query() 或 mysql_query() 執行語句后立即調用。它返回 上一個更改、刪除或插入的行數 語句(如果是 UPDATE、DELETE 或 INSERT)。對于 SELECT 語mysql_affected_rows() 有效 像 mysql_num_rows()。
對于 UPDATE 語句, 默認情況下,affected-rows 值是實際的行數 改變。如果在以下情況下指定 mysql_real_connect() 的標志 連接到 mysqld,受影響的行 value 是“找到”的行數;那是 與子句匹配。CLIENT_FOUND_ROWSWHERE
對于 REPLACE 語句, 如果新行替換了舊行,則 affected-rows 值為 2, 因為在這種情況下,在重復項之后插入了一行 已刪除。
uint64_t mysql_num_rows(MYSQL_RES *result)
返回結果集中的行數。
4.2mysql_store_result與mysql_free_result
MYSQL_RES *mysql_store_result(MYSQL *mysql);
參數說明
mysql: 指向 MYSQL 結構的指針,該結構體應已通過 mysql_real_connect 函數建立了與 MySQL 服務器的連接,并已成功執行了一個查詢(如通過 mysql_query)。
返回值
成功: 返回一個指向 MYSQL_RES 結構的指針,這個結構包含了從服務器返回的所有結果數據。
失敗 或 查詢沒有產生結果集(例如執行的是 UPDATE 或 DELETE 語句): 返回 NULL。
如何將行和列的數據從結果集中取出, 需要使用其他函數
注:mysql_store_result
函數只會返回與最近一次通過 mysql_query
(或其他發送 SQL 語句的函數)執行的查詢相關的結果。它不會存儲或回溯到之前的查詢結果,而是專注于最后執行的查詢。
注意事項
- 內存管理:使用
mysql_store_result
后,必須在不再需要結果集時調用mysql_free_result
來釋放內存。- 性能考量:由于
mysql_store_result
會將所有結果數據存儲在客戶端內存中,對于返回大量數據的查詢,這可能會消耗大量內存和網絡資源。如果處理大型數據集,可能需要考慮使用mysql_use_result
,該函數允許逐行檢索數據,從而減少內存占用。- 錯誤處理:始終檢查
mysql_store_result
的返回值,并使用mysql_error
函數來診斷錯誤。通過
mysql_store_result
,你可以方便地在客戶端處理來自 MySQL 服務器的數據,但務必注意資源管理和錯誤處理,以確保應用程序的穩定性和效率。
void mysql_free_result(MYSQL_RES *result);
參數說明
result: 指向 MYSQL_RES 結構的指針,該結構包含了之前查詢的結果集。
mysql_free_result
函數是 MySQL C API 中用來釋放由 mysql_store_result
或 mysql_use_result
函數分配的結果集內存的函數。這是清理和資源管理的重要一步,確保在查詢處理完成后不會造成內存泄漏。
當使用 mysql_store_result
或 mysql_use_result
從 MySQL 服務器獲取查詢結果后,相關的數據會被存儲在 MYSQL_RES
結構中。這個結構占用一定的內存空間,當數據處理完畢后,應該使用 mysql_free_result
來釋放這些內存。如果不這樣做,每次查詢后未釋放的內存會累積,最終可能導致內存不足或程序崩潰。
實際使用
#include <mysql.h>
#include <iostream>int main() {MYSQL *conn;MYSQL_RES *res;MYSQL_ROW row;conn = mysql_init(NULL);if (!conn) {std::cerr << "MySQL initialization failed." << std::endl;return 1;}if (!mysql_real_connect(conn, "localhost", "user", "password", "database", 0, NULL, 0)) {std::cerr << "Failed to connect to database: " << mysql_error(conn) << std::endl;mysql_close(conn);return 1;}if (mysql_query(conn, "SELECT id, name FROM users")) {std::cerr << "Query failed: " << mysql_error(conn) << std::endl;mysql_close(conn);return 1;}res = mysql_store_result(conn);if (!res) {std::cerr << "Failed to retrieve result set: " << mysql_error(conn) << std::endl;mysql_close(conn);return 1;}while ((row = mysql_fetch_row(res))) {std::cout << "ID: " << row[0] << ", Name: " << row[1] << std::endl;}// After processing the results, free the memory.mysql_free_result(res);mysql_close(conn);return 0;
}
注意事項
- 只釋放一次:確保對每個
MYSQL_RES
結構只調用一次mysql_free_result
。重復釋放可能會導致未定義行為或程序崩潰。- 適時釋放:盡可能在數據處理完畢后立即釋放結果集,特別是在處理多個查詢的情況下,避免不必要的內存占用。
- 檢查
NULL
:如果mysql_store_result
或mysql_use_result
返回NULL
,表明沒有結果集需要處理,因此不應該調用mysql_free_result
整體的工作流程
- 執行查詢:首先使用
mysql_query
執行一個 SQL 查詢。- 檢索結果:使用
mysql_store_result
檢索查詢結果并存儲在MYSQL_RES *
結構中。- 處理數據:通過循環等方式處理這些結果。
- 釋放資源:使用
mysql_free_result
釋放MYSQL_RES *
結構占用的內存。- 重復操作:如果需要再次查詢,回到第一步,執行新的
mysql_query
,然后使用mysql_store_result
檢索新的結果。
值得注意的是如果你在調用 mysql_store_result
之后沒有使用 mysql_free_result
來釋放結果集的內存,然后再次進行查詢并調用 mysql_store_result
,這將導致內存泄漏。這是因為每次調用 mysql_store_result
都會從 MySQL 服務器獲取新的結果數據,并在客戶端為這些數據分配新的內存。如果舊的結果集沒有被適當釋放,那么這部分內存仍然被占用,盡管你已經無法再訪問到這部分數據。
4.3mysql_use_result()
MYSQL_RES *mysql_use_result(MYSQL *mysql)
參數說明
mysql: 指向 MYSQL 結構的指針,該結構表示一個已連接的 MySQL 數據庫。
返回值
成功:返回一個指向 MYSQL_RES 結構的指針,該結構代表結果集。
失敗:返回 NULL,并且可以通過 mysql_error 函數獲取錯誤信息。
while ((row = mysql_fetch_row(res))) {std::cout << "ID: " << row[0] << ", Name: " << row[1] << std::endl;
}
- 逐行處理:
mysql_use_result
逐行讀取結果集,這意味著你不能在獲取完整結果集之前執行其他查詢,否則會導致未定義行為。- 資源釋放:使用
mysql_use_result
后,一定要調用mysql_free_result
釋放結果集,確保內存資源被適當管理。- 網絡延遲:因為
mysql_use_result
逐行讀取數據,受網絡延遲的影響可能會比mysql_store_result
慢,但對于大結果集它能顯著降低內存占用。
mysql_use_result
與 mysql_store_result
都是用來處理查詢結果集的函數,但它們在處理方式上有以下區別:
mysql_store_result
:一次性將整個結果集從服務器讀取到客戶端內存中,適用于結果集較小的情況,因為它會在客戶端占用較多內存。mysql_use_result
:逐行從服務器讀取結果集,適用于結果集較大的情況,因為它不會將整個結果集一次性加載到內存中,節省了內存占用。
4.4mysql_field_count()
在第三部分我們看到mysql_query不僅可以使用SELECT SQL語句還可以使用INSERT語句,我們對于查詢語句的列數和是否是查詢語句是有一定的判斷需求的
unsigned int mysql_field_count(MYSQL *mysql)
- 返回一個
unsigned int
值,表示最近執行的查詢返回的列數。如果沒有活動的查詢或查詢沒有返回任何結果,則返回 0。
注意事項
- 正確的上下文:
mysql_field_count
應該在成功執行查詢之后調用,以確保它返回正確的列數。如果在沒有活動查詢的情況下調用它,返回值將是 0。- 結果集處理:當你使用
mysql_store_result
或mysql_use_result
來獲取結果集時,使用mysql_field_count
可以幫助你動態地處理結果集中的數據。- 查詢類型:對于不返回結果集的查詢(如
INSERT
、UPDATE
、DELETE
),mysql_field_count
返回 0。
五、關閉MySQL
void mysql_close(MYSQL *mysql)
當你完成了數據庫操作并不再需要與數據庫的連接時,應該調用 mysql_close
來關閉連接。這個調用確保所有的客戶端資源被適當清理,包括內部緩沖區和連接句柄。如果不關閉連接,可能會導致資源泄漏。
void mysql_library_end(void);
在所有數據庫連接都已通過 mysql_close
關閉后,應調用 mysql_library_end
來清理 MySQL 客戶端庫使用的所有資源。這個函數主要用于多線程環境中,在所有線程都完成數據庫操作并關閉連接后,由主線程調用以確保所有的客戶端庫資源被正確釋放。
使用和區別
使用場景:
mysql_close
用于關閉單個數據庫連接;mysql_library_end
用于在程序結束前清理客戶端庫。調用時機:
mysql_close
:每個數據庫連接在不再需要時應該被關閉。
mysql_library_end
:在程序結束,所有數據庫連接都已關閉后調用。
值得注意的是即使在單線程應用程序中,依然推薦在程序結束時調用 mysql_library_end
。這個函數的作用不僅限于多線程環境,它負責清理 MySQL 客戶端庫使用的全局資源,確保所有初始化時分配的資源被適當釋放,這包括內部數據結構、緩沖區等。
六、錯誤處理
mysql_errno()和
mysql_error()
mysql_errno()
返回最近一次 MySQL 函數調用所產生的錯誤代碼。這個錯誤代碼是一個整數值,表示特定類型的錯誤。
unsigned int mysql_errno(MYSQL *mysql);
返回一個 `unsigned int` 類型的錯誤代碼。如果沒有錯誤發生,返回值為 `0`。
mysql_error()
返回最近一次 MySQL 函數調用所產生的錯誤信息字符串。這個字符串描述了具體的錯誤情況,通常比錯誤代碼更易讀和理解。
const char *mysql_error(MYSQL *mysql);
返回一個指向描述錯誤的字符串的指針。如果沒有錯誤發生,返回一個空字符串。
通過使用 mysql_errno()
和 mysql_error()
,你可以更詳細地了解數據庫操作中的錯誤,幫助調試和改進程序的錯誤處理能力。這兩個函數在處理復雜數據庫交互時尤為重要,因為它們可以提供具體的錯誤信息和錯誤代碼,有助于定位和解決問題。