ODBC API异步SQLFetch实现问询:仿SSMS分步填充网格
实现异步SQLFetch()来逐步填充网格
当然可以实现异步SQLFetch()!这正是达成你想要的「像SSMS那样逐行实时填充网格」效果的核心操作,和SSMS的底层逻辑是一致的。下面我会一步步给你拆解具体怎么做:
1. 先给语句对象开启异步模式
这是所有异步操作的前提——你得先告诉ODBC驱动,这个语句允许异步执行。用SQLSetStmtAttr()来设置:
SQLRETURN ret = SQLSetStmtAttr(hStmt, SQL_ATTR_ASYNC_ENABLE, (SQLPOINTER)SQL_ASYNC_ENABLE_ON, SQL_IS_UINTEGER); if (ret != SQL_SUCCESS && ret != SQL_SUCCESS_WITH_INFO) { // 这里处理属性设置失败的错误,比如用SQLGetDiagRec拿详细信息 }
2. 异步执行SQLExecDirect()并等待结果集就绪
你已经有微软的异步SQLExecDirect()示例了,这里要注意:当SQLExecDirect()不再返回SQL_STILL_EXECUTING,且状态为成功时,就说明结果集已经准备好可以开始取行了。
3. 异步调用SQLFetch()逐行获取数据
这一步就是实现实时填充的关键:
- 直接调用
SQLFetch(hStmt),如果返回SQL_STILL_EXECUTING,说明当前行的数据还在从服务器传输/处理中,这时候你别死等,可以去更新一下UI(比如刷新已经显示的行),或者让主线程处理消息避免界面卡死,过个几十毫秒再重试调用SQLFetch()。 - 如果返回
SQL_SUCCESS或SQL_SUCCESS_WITH_INFO,说明成功拿到了一行数据,直接把这行数据塞到你的网格控件里就行,然后继续调用SQLFetch()取下一行。 - 当返回
SQL_NO_DATA时,就代表所有行都取完了,结束循环。
给你一个简化的代码片段参考:
// 假设你已经完成了列绑定(SQLBindCol) while (1) { ret = SQLFetch(hStmt); if (ret == SQL_STILL_EXECUTING) { // 释放CPU资源,处理UI事件(比如Windows下的PeekMessage) Sleep(50); // 别睡太久,不然UI会卡顿 continue; } if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) { // 把绑定好的变量数据添加到网格中 AddRowToYourGrid(/* 传入当前行的列数据 */); } else if (ret == SQL_NO_DATA) { // 所有行处理完毕,退出循环 break; } else { // 处理取行失败的错误 HandleFetchError(hStmt); break; } }
4. 关键注意事项
- 别阻塞主线程:异步操作的核心意义就是不让UI卡死,所以绝对不能在主线程里写死循环一直等
SQLFetch()返回成功,一定要穿插处理UI消息或者短暂休眠。 - 语句对象独占性:一个语句对象同一时间只能进行一个异步操作,所以在异步
SQLFetch()期间,别用这个语句去执行其他SQL操作。 - 驱动兼容性:确保你用的是支持异步操作的SQL Server ODBC驱动,比如ODBC Driver 17/18 for SQL Server,这些都是完全支持的。
- 错误处理要细致:不管是
SQLExecDirect还是SQLFetch,只要返回非成功状态,都要用SQLGetDiagRec去获取具体的错误信息,方便排查问题。
内容的提问来源于stack exchange,提问作者Nat
相关产品推荐
相关产品推荐

