環境準備
// 1. 引入 ADO 類型庫 (msado15.dll)
#import "C:\\Program Files\\Common Files\\System\\ado\\msado15.dll" \
no_namespace rename("EOF", "adoEOF")
// 2. 初始化 COM
// MFC: AfxOleInit();
// 非 MFC: CoInitialize(NULL); ... CoUninitialize();
// 3. 智能指針類型
_ConnectionPtr m_pConnection;
_RecordsetPtr m_pRecordset;
_CommandPtr m_pCommand;
核心操作模式
1. 連接數據庫
try {
HRESULT hr = m_pConnection.CreateInstance(__uuidof(Connection));
if (SUCCEEDED(hr)) {
m_pConnection->ConnectionTimeout = 0; // 無超時
// Access 連接字符串
m_pConnection->Open(
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=db.mdb",
"", "", adModeUnknown);
// 創建 Command 對象
m_pCommand.CreateInstance(__uuidof(Command));
m_pCommand->CommandTimeout = 5;
m_pCommand->ActiveConnection = m_pConnection;
}
}
catch (_com_error& e) {
CString msg; msg.Format("連接失敗: %s", e.ErrorMessage());
AfxMessageBox(msg);
}
2. 關閉連接
if (m_pConnection->State) m_pConnection->Close();
m_pConnection = NULL;
3. 執行查詢獲取記錄集
try {
m_pRecordset.CreateInstance(__uuidof(Recordset));
m_pRecordset->Open(
"SELECT * FROM DemoTable",
_variant_t((IDispatch*)m_pConnection), // 連接指針
adOpenDynamic, // 游標類型
adLockOptimistic, // 鎖類型
adCmdText); // 命令類型
}
catch (_com_error* e) {
AfxMessageBox(e->ErrorMessage());
}
4. 遍歷記錄集
while (!m_pRecordset->adoEOF) {
_variant_t var;
var = m_pRecordset->GetCollect("Name");
if (var.vt != VT_NULL) strName = (LPCSTR)_bstr_t(var);
var = m_pRecordset->GetCollect("Age");
if (var.vt != VT_NULL) strAge = (LPCSTR)_bstr_t(var);
m_AccessList.AddString(strName + " --> " + strAge);
m_pRecordset->MoveNext();
}
5. 字段值獲取方式
| 方法 | 示例 | 說明 |
| GetCollect | GetCollect("Name") / GetCollect(_variant_t(0)) | 按名稱/索引獲取 |
| get_Collect | get_Collect("COLUMN_NAME") / get_Collect(long(index)) | COM 接口方法 |
| Fields 集合 | Fields->GetItem("Name")->Value | 標準 ADO 方式 |
6. 添加記錄
m_pRecordset->AddNew();
m_pRecordset->PutCollect("Name", _variant_t("張三"));
m_pRecordset->PutCollect("Age", _variant_t(25));
m_pRecordset->Update();
7. 修改記錄
m_pRecordset->EditMode = adEditInProgress;
m_pRecordset->PutCollect("Age", _variant_t(26));
m_pRecordset->Update();
8. 刪除記錄
try {
m_pRecordset->MoveFirst();
m_pRecordset->Move(1); // 第2條 (0-based)
m_pRecordset->Delete(adAffectCurrent);
m_pRecordset->Update();
}
catch (_com_error* e) { AfxMessageBox(e->ErrorMessage()); }
9. 直接執行 SQL(無記錄集)
// INSERT/UPDATE/DELETE/DDL
m_pCommand->CommandText = "DELETE FROM DemoTable WHERE Age > 30";
m_pCommand->Execute(NULL, NULL, adCmdText);
關鍵參數枚舉
| 類別 | 常用值 | 說明 |
| 游標類型 | adOpenForwardOnly(默認)、adOpenStatic、adOpenDynamic、adOpenKeyset | 動態游標支持並發、可見他人變更 |
| 鎖類型 | adLockReadOnly(默認)、adLockPessimistic、adLockOptimistic、adLockBatchOptimistic | 樂觀鎖適合低衝突 |
| 命令類型 | adCmdText、adCmdTable、adCmdStoredProc、adCmdUnknown | 指定 CommandText 解析方式 |
| 影響範圍 | adAffectCurrent、adAffectGroup、adAffectAllChapters | Delete/Update 影響範圍 |
異常處理最佳實踐
- 所有 ADO 操作包裝在
try-catch(_com_error&) 中
- 檢查
HRESULT 返回值
- 使用
_variant_t 自動管理 VARIANT 內存
- 智能指針自動
Release,無需手動管理
連接字符串示例
| 數據庫 | 連接字符串 |
| Access | Provider=Microsoft.Jet.OLEDB.4.0;Data Source=db.mdb |
| Access (ACE) | Provider=Microsoft.ACE.OLEDB.12.0;Data Source=db.accdb |
| SQL Server | Provider=SQLOLEDB;Server=.;Database=Test;UID=sa;PWD=123 |
| SQL Server (ODBC) | Driver={SQL Server};Server=.;Database=Test;UID=sa;PWD=123 |
| Oracle | Provider=OraOLEDB.Oracle;Data Source=ORCL;User ID=scott;Password=tiger |
| MySQL | Provider=MySQLProv;Data Source=test;User ID=root;Password=123 |
總結
ADO 通過 COM 智能指針提供簡潔的數據庫訪問接口。核心流程:初始化 COM → 創建連接 → 打開記錄集/執行命令 → 操作數據 → 關閉釋放。掌握連接字符串、游標/鎖類型選擇、異常處理、_variant_t 使用,即可高效開發健壯的數據庫應用。現代項目建議考慮 ADO.NET (C#) 或 OLE DB / ODBC 直接調用 (C++ 高性能場景)。