專案初始化與 COM 環境
// stdafx.h 最後加入
#import "C:\Program Files\Common Files\System\ADO\msado15.dll" \
no_namespace rename("EOF", "adoEOF")
// 對話框初始化
BOOL CAdotestDlg::OnInitDialog() {
CDialog::OnInitDialog();
::CoInitialize(NULL); // 初始化 COM 庫 (ADO 是 COM DLL)
return TRUE;
}
// 程式結束釋放
::CoUninitialize();
// 關閉記錄集/連線 (注意順序,勿重複 Close)
if (m_pRecordset) { m_pRecordset->Close(); m_pRecordset = NULL; }
if (m_pConnection) { m_pConnection->Close(); m_pConnection = NULL; }
rename("EOF", "adoEOF") 避免與其他庫的 EOF 巨集衝突;no_namespace 省略命名空間前綴。
ADO 三大智慧指標
| 指標 | 用途 | 特點 |
_ConnectionPtr | 建立連線、執行無回傳 SQL (DDL、存儲過程) | 輕量、可重用 |
_CommandPtr | 執行回傳記錄集的 SQL/存儲過程 | 可用全域連線或自帶連線字串 |
_RecordsetPtr | 記錄集物件 | 功能最完整:游標控制、鎖定、篩選、排序、書籤 |
完整查詢範例 (按鈕事件)
void CAdotestDlg::OnButton1() {
m_List.ResetContent(); // 清空 UI 列表
// 1. 建立智慧指標實例
m_pConnection.CreateInstance(__uuidof(Connection));
m_pRecordset.CreateInstance(__uuidof(Recordset));
try {
// 2. 開啟連線 (DSN 無密碼版)
m_pConnection->Open(_bstr_t("DSN=ADOTest"), _bstr_t(""), _bstr_t(""), 0);
// 有密碼版:
// m_pConnection->Open("DSN=test;UID=sa;PWD=123;", "", "", 0);
// 3. 執行 SQL 取得記錄集
CString strSql = _T("SELECT * FROM middle");
_bstr_t bstrSQL = strSql.AllocSysString();
m_pRecordset->Open(bstrSQL,
_variant_t((IDispatch*)m_pConnection, true),
adOpenDynamic, // 動態游標
adLockOptimistic, // 樂觀鎖定
adCmdText); // 文字命令
// 4. 遍歷記錄集
while (!m_pRecordset->adoEOF) {
// 取欄位值 (範例: 假設欄位 0,1,2)
_variant_t v0 = m_pRecordset->GetCollect((long)0);
_variant_t v1 = m_pRecordset->GetCollect(_T("column_name")); // 或欄位名
// 填入 UI...
m_List.AddString(...);
m_pRecordset->MoveNext();
}
}
catch (_com_error& e) {
AfxMessageBox((LPCTSTR)e.Description());
}
}
關鍵參數說明
adOpenDynamic:動態游標,可見他人異動,支援書籤、MovePrevious,開銷最大
adOpenStatic:靜態游標,快照模式,效能佳,適合報表
adOpenForwardOnly:唯前向游標,**最輕量**,適合單向讀取
adLockOptimistic:更新時才鎖定,高併發友善
adLockPessimistic:編輯即鎖定,低併發適用
adCmdText:SQL 文字;adCmdStoredProc:存儲過程;adCmdTable:資料表名
進階技巧
- 參數化命令 (防注入、重用計畫):
_CommandPtr cmd; cmd.CreateInstance(__uuidof(Command));
cmd->ActiveConnection = m_pConnection;
cmd->CommandText = "SELECT * FROM emp WHERE deptno = ?";
cmd->Parameters->Append(cmd->CreateParameter("p_deptno", adInteger, adParamInput, 4, 10));
_RecordsetPtr rs = cmd->Execute();
- 斷開式記錄集 (離線操作、減少連線佔用):
m_pRecordset->CursorLocation = adUseClient; // 客戶端游標
m_pRecordset->Open(...);
m_pRecordset->ActiveConnection = NULL; // 斷開連線
// 離線編輯、篩選、排序...
m_pRecordset->ActiveConnection = m_pConnection; // 重新連線
m_pRecordset->UpdateBatch(adAffectAllChapters); // 批次更新
- 連線池:ADO 自動池化 (ODBC 驅動程式層),連線字串完全相同即可重用。
Connection Timeout、CPTimeout (連線池逾時) 可調。
- 大量資料寫入:
adExecuteNoRecords + 參數陣列 或 UpdateBatch 批次提交。
常見坑點與對策
| 現象 | 原因 | 對策 |
| 多次 Close 導致存取違規 | 智慧指標釋放後再次呼叫 | Close 後立即設為 NULL,判斷非 NULL 才 Close |
| 中文亂碼 | 字元集轉換失敗 | 連線字串加 CharSet=UTF-8;Oracle 客戶端 NLS_LANG 設正確 |
| 游標類型不支援操作 | ForwardOnly 不能 MovePrevious | 依需求選擇 Static/Dynamic/Keyset |
| 記憶體洩漏 | COM 介面未 Release | 智慧指標自動管理,離開作用域即釋放 |
總結
ADO + 智慧指標是 VC++ 開發 Oracle 應用的**黃金組合**:語法簡潔、自動資源管理、功能完整。掌握 _ConnectionPtr/_RecordsetPtr 生命週期、游標/鎖定類型選擇、參數化命令與斷開式記錄集,即能覆蓋 95% 以上企業級開發場景。
- 上一篇文章: 使用 OLE DB 開發 Oracle 資料庫應用:ATL 模板與 MFC 類別完整實戰
- 下一篇文章: Windows 2000 Server 同機安裝 Oracle 9i 與 10g 完整實戰筆記
Copyright ©
程式碼之家 All Rights Reserved