本節說明如何使用 C API 非同步介面。在此討論中,非同步和非阻塞會被當作同義詞,同步和阻塞也是如此。
非同步 C API 函式涵蓋從伺服器連線讀取或寫入時可能會阻塞的操作:初始連線操作、傳送查詢、讀取結果等等。每個非同步函式都與其同步對應項具有相同的名稱,外加一個 _nonblocking
後綴。
mysql_fetch_row_nonblocking()
:非同步從結果集中提取下一列。mysql_free_result_nonblocking()
:非同步釋放結果集使用的記憶體。mysql_get_connect_nonblocking_stage()
:關於mysql_real_connect_nonblocking
狀態機器的資訊。mysql_next_result_nonblocking()
:非同步傳回/啟動多結果執行中的下一個結果。mysql_real_connect_nonblocking()
:非同步連線到 MySQL 伺服器。mysql_real_query_nonblocking()
:非同步執行指定為計數字串的 SQL 查詢。mysql_store_result_nonblocking()
:非同步將完整的結果集擷取到用戶端。
如果有些操作不需要非同步執行,或者非同步函式不適用,應用程式可以混合使用非同步和同步函式。
以下討論更詳細地說明如何使用非同步 C API 函式。
所有非同步 C API 函式都會傳回一個 enum net_async_status
值。傳回值可以是下列值之一,表示操作狀態:
NET_ASYNC_NOT_READY
:操作仍在進行中,尚未完成。NET_ASYNC_COMPLETE
:操作已成功完成。NET_ASYNC_ERROR
:操作因錯誤而終止。NET_ASYNC_COMPLETE_NO_MORE_RESULTS
:操作已成功完成,並且沒有更多結果可用。此狀態僅適用於mysql_next_result_nonblocking()
。
一般而言,若要使用非同步函式,請執行下列操作:
重複呼叫函式,直到它不再傳回
NET_ASYNC_NOT_READY
的狀態為止。檢查最終狀態是否表示成功完成 (
NET_ASYNC_COMPLETE
) 或錯誤 (NET_ASYNC_ERROR
)。
以下範例說明一些典型的呼叫模式。
代表一個非同步函式及其引數清單。function
(args
)
-
如果希望在操作進行時執行其他處理:
enum net_async_status status; status = function(args); while (status == NET_ASYNC_NOT_READY) { /* perform other processing */ other_processing (); /* invoke same function and arguments again */ status = function(args); } if (status == NET_ASYNC_ERROR) { /* call failed; handle error */ } else { /* call successful; handle result */ }
-
如果在操作進行時不需要執行其他處理:
enum net_async_status status; while ((status = function(args)) == NET_ASYNC_NOT_READY) ; /* empty loop */ if (status == NET_ASYNC_ERROR) { /* call failed; handle error */ } else { /* call successful; handle result */ }
-
如果函式的成功/失敗結果並不重要,而您只想確保操作已完成:
while (function (args) != NET_ASYNC_COMPLETE) ; /* empty loop */
對於 mysql_next_result_nonblocking()
,也必須考慮 NET_ASYNC_COMPLETE_NO_MORE_RESULTS
狀態,它表示操作已成功完成,並且沒有更多結果可用。使用方式如下:
while ((status = mysql_next_result_nonblocking()) != NET_ASYNC_COMPLETE) {
if (status == NET_ASYNC_COMPLETE_NO_MORE_RESULTS) {
/* no more results */
}
else if (status == NET_ASYNC_ERROR) {
/* handle error by calling mysql_error(); */
break;
}
}
在大多數情況下,非同步函式的引數與對應的同步函式的引數相同。例外情況是 mysql_fetch_row_nonblocking()
和 mysql_store_result_nonblocking()
,每個函式都比其同步對應項多一個引數。如需詳細資訊,請參閱 章節 7.4.1,「mysql_fetch_row_nonblocking()」,以及 章節 7.4.8,「mysql_store_result_nonblocking()」。
本節顯示一個 C++ 範例程式,說明如何使用非同步 C API 函式。
若要設定程式使用的 SQL 物件,請執行下列語句。視需要替換不同的資料庫或使用者;在這種情況下,您也需要對程式進行一些調整。
CREATE DATABASE db;
USE db;
CREATE TABLE test_table (id INT NOT NULL);
INSERT INTO test_table VALUES (10), (20), (30);
CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'testpass';
GRANT ALL ON db.* TO 'testuser'@'localhost';
建立一個名為 async_app.cc
的檔案,其中包含以下程式。視需要調整連線參數。
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <mysql.h>
#include <mysqld_error.h>
using namespace std;
/* change following connection parameters as necessary */
static const char * c_host = "localhost";
static const char * c_user = "testuser";
static const char * c_auth = "testpass";
static int c_port = 3306;
static const char * c_sock = "/usr/local/mysql/mysql.sock";
static const char * c_dbnm = "db";
void perform_arithmetic() {
cout<<"dummy function invoked\n";
for (int i = 0; i < 1000; i++)
i*i;
}
int main(int argc, char ** argv)
{
MYSQL *mysql_local;
MYSQL_RES *result;
MYSQL_ROW row;
net_async_status status;
const char *stmt_text;
if (!(mysql_local = mysql_init(NULL))) {
cout<<"mysql_init() failed\n";
exit(1);
}
while ((status = mysql_real_connect_nonblocking(mysql_local, c_host, c_user,
c_auth, c_dbnm, c_port,
c_sock, 0))
== NET_ASYNC_NOT_READY)
; /* empty loop */
if (status == NET_ASYNC_ERROR) {
cout<<"mysql_real_connect_nonblocking() failed\n";
exit(1);
}
/* run query asynchronously */
stmt_text = "SELECT * FROM test_table ORDER BY id";
status = mysql_real_query_nonblocking(mysql_local, stmt_text,
(unsigned long)strlen(stmt_text));
/* do some other task before checking function result */
perform_arithmetic();
while (status == NET_ASYNC_NOT_READY) {
status = mysql_real_query_nonblocking(mysql_local, stmt_text,
(unsigned long)strlen(stmt_text));
perform_arithmetic();
}
if (status == NET_ASYNC_ERROR) {
cout<<"mysql_real_query_nonblocking() failed\n";
exit(1);
}
/* retrieve query result asynchronously */
status = mysql_store_result_nonblocking(mysql_local, &result);
/* do some other task before checking function result */
perform_arithmetic();
while (status == NET_ASYNC_NOT_READY) {
status = mysql_store_result_nonblocking(mysql_local, &result);
perform_arithmetic();
}
if (status == NET_ASYNC_ERROR) {
cout<<"mysql_store_result_nonblocking() failed\n";
exit(1);
}
if (result == NULL) {
cout<<"mysql_store_result_nonblocking() found 0 records\n";
exit(1);
}
/* fetch a row synchronously */
row = mysql_fetch_row(result);
if (row != NULL && strcmp(row[0], "10") == 0)
cout<<"ROW: " << row[0] << "\n";
else
cout<<"incorrect result fetched\n";
/* fetch a row asynchronously, but without doing other work */
while (mysql_fetch_row_nonblocking(result, &row) != NET_ASYNC_COMPLETE)
; /* empty loop */
/* 2nd row fetched */
if (row != NULL && strcmp(row[0], "20") == 0)
cout<<"ROW: " << row[0] << "\n";
else
cout<<"incorrect result fetched\n";
/* fetch a row asynchronously, doing other work while waiting */
status = mysql_fetch_row_nonblocking(result, &row);
/* do some other task before checking function result */
perform_arithmetic();
while (status != NET_ASYNC_COMPLETE) {
status = mysql_fetch_row_nonblocking(result, &row);
perform_arithmetic();
}
/* 3rd row fetched */
if (row != NULL && strcmp(row[0], "30") == 0)
cout<<"ROW: " << row[0] << "\n";
else
cout<<"incorrect result fetched\n";
/* fetch a row asynchronously (no more rows expected) */
while ((status = mysql_fetch_row_nonblocking(result, &row))
!= NET_ASYNC_COMPLETE)
; /* empty loop */
if (row == NULL)
cout <<"No more rows to process.\n";
else
cout <<"More rows found than expected.\n";
/* free result set memory asynchronously */
while (mysql_free_result_nonblocking(result) != NET_ASYNC_COMPLETE)
; /* empty loop */
mysql_close(mysql_local);
}
使用類似於下列的命令編譯程式;視需要調整編譯器和選項:
gcc -g async_app.cc -std=c++11 \
-I/usr/local/mysql/include \
-o async_app -L/usr/lib64/ -lstdc++ \
-L/usr/local/mysql/lib/ -lmysqlclient
執行程式。結果應該與您在此處看到的類似,儘管您可能會看到不同數量的 dummy function invoked
執行個體。
dummy function invoked
dummy function invoked
ROW: 10
ROW: 20
dummy function invoked
ROW: 30
No more rows to process.
若要實驗此程式,請從 test_table
新增和移除列,並在每次變更後重新執行此程式。
以下限制適用於使用非同步 C API 函式:
mysql_real_connect_nonblocking()
只能用於使用下列驗證外掛程式之一進行驗證的帳戶:mysql_native_password
(已棄用)、sha256_password
或caching_sha2_password
。mysql_real_connect_nonblocking()
只能用於建立 TCP/IP 或 Unix Socket 檔案連線。傳遞至啟動非阻塞操作的非同步 C API 呼叫的輸入引數可能會在操作稍後終止之前保持使用狀態,並且在終止發生之前不應重複使用。
非同步 C API 函式不支援通訊協定壓縮。