| 類型 | 用途 | 創建方式 |
_ConnectionPtr | 數據源連接、事務控制 | CreateInstance(__uuidof(Connection)) 或 _ConnectionPtr("ADODB.Connection") |
_RecordsetPtr | 結果集操作、游標管理 | CreateInstance(__uuidof(Recordset)) |
_CommandPtr | 參數化命令、存儲過程 | CreateInstance(__uuidof(Command)) |
4. 連接字符串大全
// Access 2000/2003 (.mdb)
Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\\Data\\db.mdb;User ID=admin;Password=secret;
// Access 2007+ (.accdb)
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\\Data\\db.accdb;Persist Security Info=False;
// SQL Server (OLE DB)
Provider=SQLOLEDB;Data Source=192.168.1.100;Initial Catalog=MyDB;User ID=sa;Password=123;
// SQL Server (ODBC) - 需系統 DSN
Provider=MSDASQL;DSN=MyDSN;UID=sa;PWD=123;
// Oracle
Provider=MSDAORA;Data Source=ORCL;User ID=scott;Password=tiger;
5. 完整 CRUD 範例(帶結構化異常處理)
#include
#include // _com_error
void DemoADO() {
HRESULT hr;
_ConnectionPtr pConn;
_RecordsetPtr pRs;
try {
// 1. 創建連接
hr = pConn.CreateInstance(__uuidof(Connection));
if (FAILED(hr)) throw _com_error(hr);
// 2. 打開連接
_bstr_t connStr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=test.mdb;";
hr = pConn->Open(connStr, "", "", adModeUnknown);
if (FAILED(hr)) throw _com_error(hr);
// 3. 執行查詢
_bstr_t sql = "SELECT ID, Name, Age FROM Users WHERE Age > ?";
_CommandPtr pCmd;
pCmd.CreateInstance(__uuidof(Command));
pCmd->ActiveConnection = pConn;
pCmd->CommandText = sql;
pCmd->CommandType = adCmdText;
// 參數化查詢(防注入)
_ParameterPtr pParam = pCmd->CreateParameter(_T("@Age"), adInteger, adParamInput, 4, 18);
pCmd->Parameters->Append(pParam);
pRs = pCmd->Execute(NULL, NULL, adExecuteNoRecords);
// 4. 遍歷結果集
while (!pRs->adoEOF) {
long id = pRs->GetCollect("ID");
_bstr_t name = pRs->GetCollect("Name");
int age = pRs->GetCollect("Age");
printf("ID:%d Name:%s Age:%d\n", id, (LPCTSTR)name, age);
pRs->MoveNext();
}
// 5. 插入示例
sql = "INSERT INTO Users (Name, Age) VALUES (?, ?)";
pCmd->CommandText = sql;
pCmd->Parameters->Clear();
pCmd->Parameters->Append(pCmd->CreateParameter(_T("@Name"), adVarWChar, adParamInput, 50, _T("張三")));
pCmd->Parameters->Append(pCmd->CreateParameter(_T("@Age"), adInteger, adParamInput, 4, 25));
pCmd->Execute(NULL, NULL, adExecuteNoRecords);
} catch (_com_error &e) {
// 統一異常處理
_bstr_t errSrc = e.Source();
_bstr_t errDesc = e.Description();
printf("ADO 錯誤: 來源=%s 描述=%s 代碼=0x%08X\n",
(LPCTSTR)errSrc, (LPCTSTR)errDesc, e.Error());
}
// 6. 清理(智能指針自動 Release,但顯式關閉更佳)
if (pRs && pRs->State) pRs->Close();
if (pConn && pConn->State) pConn->Close();
}
6. 關鍵技術細節
- 變體類型
_variant_t/_bstr_t:自動管理 VARIANT/BSTR 生命週期,支持隱式轉換 (long)var, (LPCTSTR)bstr。
- 游標類型與鎖定:
adOpenForwardOnly (默認,只讀、單向、最快)
adOpenStatic (靜態快照、可回滾、不見他人變更)
adOpenDynamic (動態、實時、開銷大)
adLockReadOnly, adLockOptimistic, adLockPessimistic, adLockBatchOptimistic
- 參數化命令:
CreateParameter + Parameters->Append,徹底杜絕 SQL 注入。
- 異常捕獲:所有 ADO 方法返回
HRESULT,失敗拋 _com_error,catch(_com_error&) 統一處理。
7. 常見錯誤與對策
| 現象 | 原因 | 解決 |
| 「未註冊的類」/ CLASS_E_CLASSNOTAVAILABLE | 未安裝 MDAC / ACE Provider | 安裝 Microsoft Access Database Engine (32/64 位匹配編譯目標) |
| 「找不到安裝可用的 ISAM」 | Access 版本與 Provider 不匹配 | .mdb 用 Jet 4.0,.accdb 用 ACE 12.0 |
| 多次 Close 導致錯誤 | State 未檢查 | if (pConn->State) pConn->Close(); |
| 中文亂碼 | 字符集不一致 | 連接串加 ;Charset=GBK 或使用 _bstr_t 正確轉換 |
8. 進階主題
- 斷開連接記錄集:
pRs->ActiveConnection = NULL 後可離線操作,適合傳遞給 UI 層。
- 批量更新:
adLockBatchOptimistic + UpdateBatch。
- 事務:
pConn->BeginTrans() / CommitTrans() / RollbackTrans()。
- 存儲過程:
CommandType = adCmdStoredProc,Parameters->Refresh() 自動獲取參數元數據。
掌握 ADO 智能指針模式,能讓數據庫代碼既安全又優雅,是 VC++ 數據訪問層的標準選擇。
- 上一篇文章: VC++ DLL 編程深度解析(三):MFC Regular DLL 與資源模塊狀態切換
- 下一篇文章: ADO 訪問帶密碼 Access 數據庫的完整實現代碼
Copyright ©
程式碼之家 All Rights Reserved