核心代碼
// 建立 Recordset
m_pRecordSet.CreateInstance(__uuidof(Recordset));
#ifdef _DEBUG
if (!m_pRecordSet) {
AfxMessageBox(_T("Recordset 建立失敗,檢查 COM 初始化"));
return;
}
#endif
CString sql = _T("TestGet"); // 預存程序名
long recordCount = 0;
try {
// 關鍵:adCmdStoredProc 告知 ADO 這是預存程序
m_pRecordSet->Open(
(_variant_t)sql,
_variant_t((IDispatch*)m_pConnection, TRUE),
adOpenStatic, adLockOptimistic, adCmdStoredProc
);
recordCount = m_pRecordSet->GetRecordCount();
if (!m_pRecordSet->adoEOF) {
for (long i = 0; i < recordCount; ++i) {
// 取欄位值:GetCollect 比 Fields["Name"]->Value 更快
_variant_t val = m_pRecordSet->GetCollect(_T("Account"));
AfxMessageBox((LPCTSTR)(_bstr_t)val);
m_pRecordSet->MoveNext();
}
}
m_pRecordSet->Close();
}
catch (_com_error& e) {
CString err;
err.Format(_T("開啟記錄集異常:%s\n檔案:%s 行:%d"),
e.ErrorMessage(), __FILE__, __LINE__);
AfxMessageBox(err);
}
關鍵參數解析
| 參數 | 值 | 說明 |
| CursorType | adOpenStatic | 靜態游標,支援 GetRecordCount、MoveFirst 等 |
| LockType | adLockOptimistic | 樂觀鎖定,更新時檢查衝突 |
| Options | adCmdStoredProc | **關鍵**:指定命令為預存程序,非 SQL 文本 |
若改用 SQL 直寫
CString sql = _T("SELECT Account FROM Users WHERE Active=1");
m_pRecordSet->Open(
(_variant_t)sql,
_variant_t((IDispatch*)m_pConnection, TRUE),
adOpenStatic, adLockOptimistic, adCmdText // ← 改這裡
);
效能與穩健建議
- 大量資料改用
adOpenForwardOnly + adLockReadOnly 僅前向讀取;
- 欄位存取優先用
GetCollect/GetFields 避免 COM 多次往返;
_variant_t/_bstr_t 智慧指標自動管理 BSTR/VARIANT 生命週期;
- 連接物件
m_pConnection 需提前 Open 並錯誤檢查;
- 生產環境移除
AfxMessageBox,改寫入日誌/回呼處理。