ADO 物件模型核心:**Connection** (連接) → **Command/Recordset** (執行/結果)。本文詳細解析三種執行 SQL 方式、Recordset 遍歷更新、資源管理。
_variant_t vRecordsAffected;
_RecordsetPtr pRs;
// 1. DDL: 建立資料表
pConn->Execute(L"CREATE TABLE users(ID INT, username TEXT, old INT, birthday DATETIME)",
&vRecordsAffected, adCmdText);
// 2. DML: 新增記錄
pConn->Execute(L"INSERT INTO users VALUES (1, 'Washington', 25, '1970/1/1')",
&vRecordsAffected, adCmdText);
// 3. DML: 批次更新
pConn->Execute(L"UPDATE users SET old = old + 1", &vRecordsAffected, adCmdText);
// 4. 查詢返回 Recordset
pRs = pConn->Execute(L"SELECT COUNT(*) FROM users", &vRecordsAffected, adCmdText);
_variant_t vCount = pRs->GetCollect((long)0); // 取第一欄
pRs->Close();
AfxMessageBox(CString(L"共有 ") + vCount.lVal + L" 條記錄");
_CommandPtr pCmd; pCmd.CreateInstance(L"ADODB.Command");
_variant_t vNull; vNull.vt = VT_ERROR; vNull.scode = DISP_E_PARAMNOTFOUND;
pCmd->ActiveConnection = pConn; // 關鍵:綁定連接
pCmd->CommandText = L"SELECT * FROM users WHERE old > ?"; // 參數化
pCmd->CommandType = adCmdText;
// 建立參數 (可選,若 CommandText 含 ? 需對應)
_ParameterPtr pParm = pCmd->CreateParameter(L"MinAge", adInteger, adParamInput, 4, 18);
pCmd->Parameters->Append(pParm);
_RecordsetPtr pRs = pCmd->Execute(&vNull, &vNull, adCmdText);
// 此時 pRs 只含 old > 18 的記錄
Command 核心優勢:預存程序調用 (`CommandType=adCmdStoredProc`)、參數型別安全、執行計劃重用、防 SQL 注入。
pRs->Open(L"SELECT * FROM users",
_variant_t((IDispatch*)pConn, true), // 連接指標包裝為 VARIANT
adOpenStatic, adLockOptimistic, adCmdText);
| 參數 | 常用值 | 說明 |
|---|---|---|
| CursorType | adOpenStatic(3) | 靜態快照,支援書籤/RecordCount,不見他人變更 |
| adOpenDynamic(2) | 動態,即時同步,開銷大 | |
| adOpenKeyset(1) | 鍵集,見更新不見增刪 | |
| adOpenForwardOnly(0) | 唯讀順向,最快,無 RecordCount | |
| LockType | adLockOptimistic(3) | 更新時鎖 (推薦一般編輯) |
| adLockPessimistic(2) | 編輯即鎖 (高衝突) | |
| adLockBatchOptimistic(4) | 批次更新模式 | |
| adLockReadOnly(1) | 唯讀 |
_variant_t vID, vName, vOld, vBirth;
pRs->Open(L"SELECT * FROM users", _variant_t((IDispatch*)pConn, true),
adOpenStatic, adLockOptimistic, adCmdText);
// 1. 遍歷輸出
while (!pRs->adoEOF) {
vID = pRs->GetCollect((long)0); // 索引 0-based
vName = pRs->GetCollect(L"username"); // 或欄位名
vOld = pRs->GetCollect(L"old");
vBirth = pRs->GetCollect(L"birthday");
if (vID.vt!=VT_NULL && vName.vt!=VT_NULL && vOld.vt!=VT_NULL && vBirth.vt!=VT_NULL)
TRACE(L"id:%d, 姓名:%s, 年齡:%d, 生日:%s\n", vID.lVal, (LPCTSTR)_bstr_t(vName), vOld.lVal, (LPCTSTR)_bstr_t(vBirth));
pRs->MoveNext();
}
// 2. 刪除第一筆
pRs->MoveFirst();
pRs->Delete(adAffectCurrent);
// 3. 新增三筆
for (int i=0; i<3; ++i) {
pRs->AddNew();
pRs->PutCollect(L"ID", _variant_t(i+10));
pRs->PutCollect(L"username", _variant_t(L"葉利欽"));
pRs->PutCollect(L"old", _variant_t(71));
pRs->PutCollect(L"birthday", _variant_t(L"1930-3-15"));
}
// 4. 修改第二筆年齡
pRs->Move(1, _variant_t(adBookmarkFirst)); // 從第一筆移動 1 筆
pRs->PutCollect(L"old", _variant_t(45));
pRs->Update(); // 寫入資料庫
pRs->Close();
pConn->Close();
// 智能指標離開作用域自動 Release,亦可手動 pRs = NULL; pConn = NULL;
ADO 三大物件操作核心在於:**Connection 管理連接池與事務、Command 封裝參數化邏輯與預存程序、Recordset 提供豐富游標/鎖定模式的結果集操作**。熟練掌握 `Execute`/`Open`/`AddNew/Update/Delete` 與游標鎖定選擇,即可應對 90% 資料庫應用場景。下篇深入綁定、事務、BLOB、預存程序等進階主題。