本节介绍如何使用 C API 异步接口。在此讨论中,异步和非阻塞用作同义词,同步和阻塞也是如此。
异步 C API 函数涵盖在从服务器连接读取或写入时可能阻塞的操作:初始连接操作、发送查询、读取结果等。每个异步函数与其对应的同步函数同名,外加一个
_nonblocking
后缀:
mysql_fetch_row_nonblocking()
: 从结果集中异步获取下一行。mysql_free_result_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()
and
mysql_store_result_nonblocking()
,与同步对应物相比,它们中的每一个都需要一个额外的参数。有关详细信息,请参阅
第 7.4.1 节,“mysql_fetch_row_nonblocking()”和
第 7.4.6 节,“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 套接字文件连接。传递给启动非阻塞操作的异步 C API 调用的输入参数可能会一直使用,直到操作稍后终止,并且在终止发生之前不应被重用。
异步 C API 函数不支持协议压缩。