前言
從 Jet Engine 到 Oracle,VC++ 6.0 提供了五套主流資料庫程式介面。本文從架構、核心類、程式碼量、部署、效能五個維度逐項拆解,並給出實戰選型建議。
1. ODBC API:最接近金屬的標準介面
核心流程
SQLAllocHandle(SQL_HANDLE_ENV) → 初始化環境
SQLAllocHandle(SQL_HANDLE_DBC) → 分配連線句柄
SQLSetConnectAttr → 設定屬性(逾時、自動認可等)
SQLConnect / SQLDriverConnect / SQLBrowseConnect → 三種連線模式
SQLAllocHandle(SQL_HANDLE_STMT) → 配置陳述句柄
SQLExecDirect / SQLPrepare + SQLExecute → 執行 SQL
SQLBindCol / SQLGetData → 綁定/取回欄位
- 清理:
SQLFreeHandle 逆序釋放 STMT → DBC → ENV
特點
- 功能最全:異步、事務、遊標類型、描述符全支援
- 代碼冗長:簡單查詢也需 50+ 行樣板碼
- 部署輕量:僅需目標 DB 的 ODBC 驅動
2. MFC ODBC:Visual Studio 經典封裝,生產力巔峰
四大核心類
| 類別 | 職責 | 關鍵方法 |
CDatabase | 連線管理 | OpenEx()、BeginTrans/CommitTrans/Rollback、Close() |
CRecordset | 記錄集操作 | Open()、MoveNext/Prev/First/Last、AddNew/Edit/Update/Delete、Requery |
CRecordView | 資料綁定視圖 | 對話框模板 + DDX/DDV + RFX,零代碼顯示/編輯 |
CDBException | 異常封裝 | m_nRetCode (ODBC 碼)、m_strError、m_strStateNativeOrigin |
兩種記錄集模式
- Snapshot:靜態快照,不反映他人變更,適合報表
- Dynaset:動態游標,可見他人更新/插入/刪除,適合互動式編輯
實戰模式
// 1. 開啟連線
CDatabase db; db.OpenEx(_T("DSN=Sales;UID=sa;PWD=123"));
// 2. 宣告衍生自 CRecordset 的類(ClassWizard 自動生成)
class CMySet : public CRecordset {
public:
CString m_Name; int m_Age;
// RFX 對應欄位...
};
// 3. 使用
CMySet rs(&db); rs.Open(CRecordset::dynaset);
while (!rs.IsEOF()) { /* 處理 rs.m_Name */ rs.MoveNext(); }
rs.Close(); db.Close();
3. DAO (MFC DAO):Access 專屬的黃金搭檔
核心類對照表
| MFC ODBC | MFC DAO | 備註 |
| CDatabase | CDaoDatabase | 連線管理 |
| CRecordset | CDaoRecordset | 記錄集 |
| CRecordView | CDaoRecordView | 資料綁定視圖 |
| CDBException | CDaoException | 異常 |
| — | CDaoTableDef | 表定義操作(建立/刪除/索引) |
| — | CDaoQueryDef | 查詢定義(參數查詢、SQL Pass-through) |
| — | CDaoWorkspace | 工作區/交易管理(支援多工作區隔離) |
關鍵差異
- DAO 直接操作 Jet/ACE 引擎,無 ODBC 層轉換,**本地 Access 效能最優**
- 支援
CDaoTableDef 建立表、索引、關係,**結構操作極其方便**
- 微軟 2000 年後停止增強,**新專案勿用**
4. OLE DB:通用資料存取的 COM 基石
三大角色
- Data Provider:實作
IRowset 等介面,暴露資料
- Consumer:使用
IRowset、ICommand、ITransaction 存取資料
- Service Provider:中介服務(資料指標引擎、查詢處理器、分散式交易協調器)
核心介面
Enumerator -> 列舉可用資料源
DataSource -> 建立 Session
Session -> 建立 Transaction、Command、Rowset
Command -> 執行文字命令 (SQL) 產生 Rowset
Rowset -> 逐列存取、尋找、書籤、更新
Error -> 詳細錯誤資訊 (IErrorInfo)
ATL OLE DB 消費者/提供者範本
- 消費者:
CCommand<CAccessor<MyAccessor> > 靜態綁定欄位,編譯期型別安全
- 提供者:實作
IRowsetImpl 等模板,快速打造自訂 Provider
痛點
純 COM 程式碼極其冗長(參考計數、QueryInterface、HRESULT 檢查),除非寫 Provider 或極致效能場景,**消費者端強烈建議改用 ADO**。
5. ADO:簡潔物件模型,跨語言通用
七大核心物件
| 物件 | 用途 |
| Connection | 連線、交易、命令執行 |
| Command | 參數化命令、預存程序 |
| Recordset | 資料集:游標類型、鎖定類型、離線模式 |
| Field | 欄位值、屬性、型別 |
| Parameter | 命令參數輸入/輸出 |
| Property | 動態屬性集合 |
| Error | 詳細錯誤資訊 |
VC++ 使用模式
// 需 #import "msado15.dll" no_namespace rename("EOF", "adoEOF")
_ConnectionPtr cn; cn.CreateInstance(__uuidof(Connection));
cn->Open("Provider=SQLOLEDB;Data Source=.;Initial Catalog=Test;UID=sa;PWD=123", "", "", adConnectUnspecified);
_RecordsetPtr rs; rs.CreateInstance(__uuidof(Recordset));
rs->Open("SELECT * FROM Users", cn, adOpenStatic, adLockOptimistic, adCmdText);
while (!rs->adoEOF) {
_variant_t v = rs->GetFields()->GetItem("Name")->Value;
printf("%s\n", (_bstr_t)v);
rs->MoveNext();
}
rs->Close(); cn->Close();
優勢
- 物件模型扁平、直覺,**幾行代碼完成 CRUD**
- 支援離線記錄集(
CursorLocation = adUseClient),斷線後仍可操作、批次更新
- ASP/Classic、VBScript、JScript、VB6、VC++ 通用,**團隊協作零門檻**
綜合對比雷達圖(1-5 分)
| 維度 | ODBC API | MFC ODBC | DAO | OLE DB | ADO |
| 效能上限 | ★★★★★ | ★★★★ | ★★★ (本地) | ★★★★★ | ★★★★ |
| 開發效率 | ★ | ★★★★ | ★★★ | ★ | ★★★★★ |
| 部署輕量 | ★★★★★ | ★★★ | ★★★ | ★★★ | ★★★★ |
| 資料源廣度 | ★★ (關聯) | ★★ (關聯) | ★ (Jet) | ★★★★★ | ★★★★★ |
| 學習曲線 | ★★★★★ (陡) | ★★★ | ★★ | ★★★★★ (陡) | ★★ |
| 現代維護 | ★★★★★ | ★★★ | ☆ (棄用) | ★★★ | ★★★ |
實戰選型速查表
- 高併發 C++ 服務、需精細控制遊標/異步/事務 → ODBC API (+ 連線池)
- MFC 桌面專案、團隊熟練 ClassWizard → MFC ODBC(最快產出)
- 操作 Access/Excel、單機輕量部署 → ADO + ACE OLEDB
- Web/ASP 維護、腳本語言混編 → ADO
- 自建 Provider、整合非關聯源 (XML、LDAP、自定義) → OLE DB / ATL
- 新專案、跨平台、現代 C++ → 標準 ODBC + 現代封裝 或 **遷移至 .NET Core / Entity Framework**
結語
技術演進的主線是 「層層封裝、降低門檻、擴大適用面」:ODBC API 奠基標準 → OLE DB 統一異構源 → ADO 簡化 COM 物件模型 → ADO.NET / EF 進入托管/ORM 時代。理解這條主線,你就能在任何時代做出最合適的技術選擇——**不為了炫技用底層,不為了偷懶濫用高層,恰到好處才是架構師的本色**。