首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

OCCI 遷移 OCI 實戰:Windows 下環境初始化失敗與自製 ocipp 封裝庫

     編輯:關於C語言

背景與痛點

專案原定 Linux 部署,臨時切換 Windows 平台。OCCI 11 與 VC9 相容性不佳,Environment 初始化即報錯,經長時間嘗試無果,決定放棄 OCCI,改用底層 OCI 並自行封裝輕量級 C++ 包裝器 ocipp(Oracle C++ Interface Parallel/Simple)。

踩坑經驗:雙連線調試導致死結

同時開啟 SQL*Plus 與 ocipp 程式測試 DML(UPDATE/DELETE)時,程式卡在 execute 呼叫。根因:SQL*Plus 預設手動提交,而 ocipp 採 OCI_COMMIT_ON_SUCCESS 自動提交,兩者鎖衝突。教訓:調試 OCI 介面時,切勿同時開啟另一資料庫會話進行未提交的寫入操作。

ocipp 架構設計

三大核心類別:

  • Environment:管理 OCI 環境句柄與錯誤句柄,單例模式
  • Connection:封裝伺服器連線、服務上下文、會話認證
  • Statement:支援字串綁定/定義、執行、逐行抓取

僅支援 std::string 類型的定義與綁定,適合純文字資料場景,代碼精簡、風險自負。

關鍵實作片段

Environment 建立與錯誤處理

Environment::Environment(unsigned int mode) : _env(NULL), _err(NULL) {
    makeEnvironment(mode);
}

void Environment::makeEnvironment(unsigned int mode) {
    int ret = OCIEnvCreate(&_env, mode, NULL, NULL, NULL, NULL, 0, NULL);
    if (ret != OCI_SUCCESS || _env == NULL)
        throw Exception(ret, "create Environment failed.");
    ret = OCIHandleAlloc((const void*)_env, (void**)&_err, OCI_HTYPE_ERROR, 0, NULL);
    if (ret != OCI_SUCCESS || _err == NULL)
        throw Exception(ret, _err, "create Error failed.");
}

Connection 建立流程


Connection* Environment::makeConnection(const string& user, const string& passwd, const string& server) {
    Connection *conn = new Connection(this);
    // 1. 分配 Server Handle
    // 2. 分配 Service Context Handle
    // 3. OCIServerAttach 連接伺服器
    // 4. 設定 SVCCTX 的 OCI_ATTR_SERVER
    // 5. 分配 Session Handle、設定 Username/Password
    // 6. OCISessionBegin 開啟會話
    // 7. 設定 SVCCTX 的 OCI_ATTR_SESSION
    return conn;
}

Statement 綁定、定義與執行


int Statement::bindString(unsigned int pos, const string& val) {
    OCIBind* bd = NULL;
    int ret = OCIBindByPos(_stmt, &bd, _conn->getEnvironment()->getError(), pos,
                           (void*)val.c_str(), val.size() + 1, SQLT_STR,
                           NULL, NULL, NULL, 0, NULL, OCI_DEFAULT);
    if (ret != OCI_SUCCESS) throw Exception(ret, ..., "bind String failed.");
    return 0;
}

int Statement::execute() {
    unsigned short type;
    OCIAttrGet(_stmt, OCI_HTYPE_STMT, &type, 0, OCI_ATTR_STMT_TYPE, _conn->getEnvironment()->getError());
    int ret = OCIStmtExecute(_conn->getSvc(), _stmt, _conn->getEnvironment()->getError(),
                             (type != OCI_STMT_SELECT ? 1 : 0), 0, NULL, NULL, OCI_COMMIT_ON_SUCCESS);
    if (ret != OCI_SUCCESS) throw Exception(ret, ..., "execute Stmt failed.");
    return 0;
}

總結

ocipp 雖非生產級庫,但展示了 OCI 核心流程:環境→連線→陳述式→綁定/定義→執行→抓取→清理。若需健壯方案,建議直接使用 OCCI(新版已修復 VC 相容性)或成熟第三方庫如 OTL、SOCI。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved