一、環境配置
1. 安裝 Instant Client (30MB 輕量版)
- 下載 Basic、SDK、SQL*Plus 套件
- 解壓至目錄 (如
D:\oracle\instantclient_19_3)
- 設定環境變數:
ORACLE_HOME, PATH 加入該目錄, NLS_LANG
2. Visual Studio 專案設定
- Include 目錄加入
$(ORACLE_HOME)\sdk\include
- Library 目錄加入
$(ORACLE_HOME)\sdk\lib\msvc
- 連結器輸入加入
oci.lib
二、核心句柄體系 (父子關係)
| 句柄類型 | 常數 | 用途 |
| Environment | OCI_HTYPE_ENV | 頂層環境,所有句柄父節點 |
| Error | OCI_HTYPE_ERROR | 記錄 OCI 函數錯誤資訊 |
| Server | OCI_HTYPE_SERVER | 實體連線端點 |
| Service Context | OCI_HTYPE_SVCCTX | 服務上下文,含 Server/Session/Trans |
| Session | OCI_HTYPE_SESSION | 使用者認證與權限 |
| Transaction | OCI_HTYPE_TRANS | 交易環境 |
| Statement | OCI_HTYPE_STMT | SQL/PLSQL 執行上下文 |
| Bind/Define | 隱式建立 | 輸入/輸出變數綁定 |
三、連線標準流程
1. OCIEnvCreate(&envhp, OCI_DEFAULT, ...);
2. OCIHandleAlloc(envhp, &errhp, OCI_HTYPE_ERROR, ...);
3. OCIHandleAlloc(envhp, &srvhp, OCI_HTYPE_SERVER, ...);
4. OCIServerAttach(srvhp, errhp, (text*)"DB_TNS", strlen("DB_TNS"), OCI_DEFAULT);
5. OCIHandleAlloc(envhp, &svchp, OCI_HTYPE_SVCCTX, ...);
6. OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, srvhp, 0, OCI_ATTR_SERVER, errhp);
7. OCIHandleAlloc(envhp, &usrhp, OCI_HTYPE_SESSION, ...);
8. OCIAttrSet(usrhp, OCI_HTYPE_SESSION, (text*)"user", strlen("user"), OCI_ATTR_USERNAME, errhp);
9. OCIAttrSet(usrhp, OCI_HTYPE_SESSION, (text*)"pwd", strlen("pwd"), OCI_ATTR_PASSWORD, errhp);
10. OCISessionBegin(svchp, errhp, usrhp, OCI_CRED_RDBMS, OCI_DEFAULT);
11. OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, usrhp, 0, OCI_ATTR_SESSION, errhp);
-- 連線完成,可執行 SQL
四、執行 SQL 標準流程
1. OCIHandleAlloc(envhp, &stmthp, OCI_HTYPE_STMT, ...);
2. OCIStmtPrepare(stmthp, errhp, (text*)sql, strlen(sql), OCI_NTV_SYNTAX, OCI_DEFAULT);
3. OCIBindByPos(stmthp, &bndhp, errhp, pos, &val, size, SQLT_CHR, ...); -- 綁定輸入
4. OCIDefineByPos(stmthp, &defhp, errhp, pos, &out_val, size, SQLT_CHR, ...); -- 綁定輸出
5. OCIStmtExecute(svchp, stmthp, errhp, iters, 0, NULL, NULL, OCI_DEFAULT);
6. while (OCIStmtFetch(stmthp, errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT) != OCI_NO_DATA) { ... }
7. OCIHandleFree(stmthp, OCI_HTYPE_STMT);
五、關鍵屬性設定/讀取
OCI_ATTR_SERVER / OCI_ATTR_SESSION / OCI_ATTR_TRANS:Service Context 組合
OCI_ATTR_USERNAME / OCI_ATTR_PASSWORD:Session 認證
OCI_ATTR_ROWS_FETCHED:實際擷取行數
OCI_ATTR_ROW_COUNT:DML 影響行數
OCI_ATTR_STMT_TYPE:SQL 類型 (SELECT/INSERT/UPDATE/DELETE/BEGIN)
六、錯誤處理
sb4 errcode; text errbuf[1024];
OCIErrorGet(errhp, 1, NULL, &errcode, errbuf, sizeof(errbuf), OCI_HTYPE_ERROR);
printf("ORA-%05d: %s\n", errcode, errbuf);
七、批量操作 (Array DML / Array Fetch)
- 定義結構陣列
struct Row { char name[20]; int age; } rows[1000];
OCIBindByPos 綁定陣列位址,maxarr_len=1000
OCIBindArrayOfStruct 設定結構大小跳躍
OCIStmtExecute(svchp, stmthp, errhp, 1000, ...) 一次執行 1000 筆
- 同理
OCIDefineArrayOfStruct 批量擷取
八、交易控制
OCITransCommit(svchp, errhp, OCI_DEFAULT);
OCITransRollback(svchp, errhp, OCI_DEFAULT);
九、斷開連線
OCISessionEnd(svchp, errhp, usrhp, OCI_DEFAULT);
OCIServerDetach(srvhp, errhp, OCI_DEFAULT);
OCIHandleFree(usrhp, OCI_HTYPE_SESSION);
OCIHandleFree(srvhp, OCI_HTYPE_SERVER);
OCIHandleFree(svchp, OCI_HTYPE_SVCCTX);
OCIHandleFree(errhp, OCI_HTYPE_ERROR);
OCIHandleFree(envhp, OCI_HTYPE_ENV);
十、常見陷阱與最佳實務
- 每個 Statement 用完即
FREE,避免 Bind/Define 句柄洩漏
- 輸出變數可能為 NULL,**必須提供 Indicator (sb2*)**,否則無法正確讀取 NULL 值
- 非阻塞模式 (
OCI_ATTR_NONBLOCKING_MODE) 需輪詢 OCI_STILL_EXECUTING,一般用阻塞模式即可
- 模式旗標可組合:
OCI_THREADED | OCI_OBJECT (空間資料需 OBJECT)
- OCI 類型對應:
ub1/sb1(1B), ub2/sb2(2B), ub4/sb4(4B)
參考資源