本节介绍如何使用 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
)
-
如果需要在操作进行时执行其他处理
Press CTRL+C to copyenum 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 */ }
-
如果不需要在操作进行时执行其他处理
Press CTRL+C to copyenum 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 */ }
-
如果函数成功/失败结果无关紧要,并且您只想确保操作已完成
Press CTRL+C to copywhile (function (args) != NET_ASYNC_COMPLETE) ; /* empty loop */
对于 mysql_next_result_nonblocking()
,还需要考虑 NET_ASYNC_COMPLETE_NO_MORE_RESULTS
状态,它指示操作已成功完成,并且没有更多结果可用。使用方法如下
Press CTRL+C to copywhile ((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 对象,请执行以下语句。根据需要替换不同的数据库或用户;在这种情况下,您还需要对程序进行一些调整。
Press CTRL+C to copyCREATE 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
的文件,其中包含以下程序。根据需要调整连接参数。
Press CTRL+C to copy#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); }
使用类似以下命令编译程序;根据需要调整编译器和选项
Press CTRL+C to copygcc -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
实例。
Press CTRL+C to copydummy 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 套接字文件连接。传递给启动非阻塞操作的异步 C API 调用的输入参数可能在操作在稍后终止之前一直处于使用状态,并且在终止发生之前不应重用。
异步 C API 函数不支持协议压缩。