全部產品
Search
文件中心

ApsaraDB for OceanBase (Deprecated):C 驅動串連 OceanBase 資料庫

更新時間:Jul 01, 2024

本文介紹了如何通過 OBCI 驅動串連並使用 OceanBase 資料庫。

前提條件

  • 確保設定了基本的資料庫開發環境。

  • 確保滿足如下硬體環境:

    • 硬體平台:x86_64。

    • 作業系統:CentOS/Redhat 系 Linux 發行版 7.2。

    • 編譯器:GCC 4.8。

  • 聯絡技術支援人員擷取 OBCI 和 LibOBClient 的 RPM 安裝包。

C 驅動串連 OceanBase 資料庫

步驟一:擷取資料庫連接參數

參考 擷取串連參數 文檔,擷取相應的租戶串連參數,例如:

obclient -hxxx.xxx.xxx.xxx -P1521 -u a**** -p******

資料庫連接參數包含了訪問資料庫所需的參數資訊,在驗證範例程式碼前,可通過資料庫連接參數驗證登入資料庫,保證資訊正確。

參數說明:

  • -hOceanBase 資料庫連接的網域名稱。

  • -POceanBase 資料庫連接連接埠,Oracle 模式租戶預設是 1521。

  • -u:串連租戶的帳號。

  • -p:帳號密碼

步驟二:安裝 C 相關驅動

當您擷取 RPM 包後,在命令列工具中以 root 使用者權限執行如下命令進行 OBCI 驅動的安裝。

由於 OBCI 依賴於 LibOBClient,所以需要先安裝 LibOBClient。

$ rpm -ivh libobclient-<version>.x86_64.rpm

再安裝 OBCI。

$ rpm -ivh obci-<version>.x86_64.rpm

在預設情況下,軟體包中包含的程式與檔案將安裝在如下路徑中:

  • 標頭檔被安裝在 /u01/obclient/include 路徑下。

  • 庫檔案被安裝在 /u01/obclient/lib 路徑下。

在高版本 OBCI 安裝包中,由於著作權限制,串連過程需要使用的資料庫檔案需要安裝 Oracle Instant Client 擷取,詳細下載請參考 Oracle Instant Client Downloads

常見需要的安裝包為 basic 和 SDK 包。

  • 安裝 basic 包。

    $ rpm -ivh oracle-instantclient-basic-<version>.x86_64.rpm
  • 安裝 SDK 包

    $ rpm -ivh oracle-instantclient-devel-<version>.x86_64.rpm

步驟三:編寫範例程式碼

本文通過具體執行個體介紹在 OceanBase 資料庫 Oracle 模式下,C 語言通過 OBCI 與資料庫伺服器 OBServer 節點互動的基本方式。

  1. 初始化 OBCI 環境和線程。

    • 初始化 OBCI 程式環境

      OCIInitialize(OCI_DEFAULT, NULL, NULL, NULL, NULL)
    • 初始化環境控制代碼

      OCIEnvInit(&envhp, OCI_DEFAULT, 0, 0)
  2. 分配必要的控制代碼與資料結構。

    • 分配控制代碼

      OCIHandleAlloc(envhp, (dvoid **)&svchp, OCI_HTYPE_SVCCTX, 0, 0)
    • 伺服器環境控制代碼

      OCIHandleAlloc(envhp, (dvoid **)&srvhp, OCI_HTYPE_SERVER, 0, 0)
    • 伺服器控制代碼

      OCIHandleAlloc(envhp, (dvoid **)&authp, OCI_HTYPE_SESSION, 0, 0)
    • 交談控制代碼

      OCIHandleAlloc(envhp, (dvoid **)&errhp, OCI_HTYPE_ERROR, 0, 0)
    • 錯誤控制代碼

      OCIHandleAlloc(envhp, (dvoid **)&dschp, OCI_HTYPE_DESCRIBE, 0, 0)
  3. 建立與資料庫的串連以及建立使用者會話。

    • 設定使用者名稱

       OCIAttrSet(authp, OCI_HTYPE_SESSION, (text *)strUserName,(ub4)strlen(strUserName), OCI_ATTR_USERNAME, errhp)
    • 設定密碼

      OCIAttrSet(authp, OCI_HTYPE_SESSION, (text *)strPassword,(ub4)strlen(strPassword), OCI_ATTR_PASSWORD, errhp)
    • 設定伺服器環境控制代碼屬性

      OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX,(dvoid *)srvhp, (ub4)0, OCI_ATTR_SERVER, errhp)
      OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, (dvoid *)authp,0, OCI_ATTR_SESSION, errhp)
    • 建立會話

      OCISessionBegin(svchp, errhp, authp, OCI_CRED_RDBMS, OCI_DEFAULT)
    • 開始會話

      OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, 0, 0)
  4. 通過 SQL 與 OceanBase 伺服器交換資料,而後再做資料處理。一條 SQL 陳述式在 OBCI 應用程式中的執行步驟如下:

    1. 通過調用函數 OCIStmtPrepare() 或者 OCIStmtPrepare2() 準備 SQL 陳述式。

      OCIStmtPrepare(stmthp, errhp, (text *)sql, strlen(sql), OCI_NTV_SYNTAX,OCI_DEFAULT)
    2. 通過調用一個或者多個函數,如 OCIBindByPos() 把輸入變數的地址綁定在 DML 語句中的預留位置中。

      OCIBindByPos(stmthp, &bidhp[0], errhp, 1, &szpersonid,
       sizeof(szpersonid), SQLT_INT, NULL, NULL, NULL, 0, NULL, 0)

      或者通過 OCIBindByName() 函數進行。

      OCIBindByName(stmthp, &bidhp[0], errhp, (const OraText*)":personid", 9, &szpersonid,
       sizeof(szpersonid), SQLT_INT, NULL, NULL, NULL, 0, NULL, 0)
    3. 調用 OCIStmrExecute() 函數執行 SQL 陳述式。

      OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, (ub4)0, (CONST OCISnapshot *)0, (OCISnapshot *)0, (ub4)OCI_DEFAULT)
    4. 調用 OCIDefineByPos() 函數為 SQL 陳述式中的資料輸出項定義輸出變數。

      OCIDefineByPos(stmthp, &defhp[0], errhp, 1, &szpersonid,
        sizeof(szpersonid), SQLT_INT, &ind[0], 0, 0, OCI_DEFAULT)
    5. 調用 OCIStmtFetch() 函數來擷取查詢的結果集。

      OCIStmtFetch(stmthp, errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT)
  5. 結束使用者會話與斷開與資料庫的串連。

    • 結束會話

      OCISessionEnd(svchp, errhp, authp, (ub4)0)
    • 斷開與資料庫的串連

      OCIServerDetach(srvhp, errhp, OCI_DEFAULT)
  6. 釋放在程式中所分配的控制代碼。

    OCIHandleFree((dvoid *)dschp, OCI_HTYPE_DESCRIBE)
    OCIHandleFree((dvoid *)stmthp, OCI_HTYPE_STMT)
    OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR)
    OCIHandleFree((dvoid *)authp, OCI_HTYPE_SESSION)
    OCIHandleFree((dvoid *)svchp, OCI_HTYPE_SVCCTX)
    OCIHandleFree((dvoid *)srvhp, OCI_HTYPE_SERVER)

範例程式碼

樣本檔案 test.c 代碼內容如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>
#include "oci.h"
/*聲明控制代碼*/
OCIEnv *envhp; /*環境控制代碼*/
OCISvcCtx *svchp; /*服務環境控制代碼*/
OCIServer *srvhp; /*伺服器控制代碼*/
OCISession *authp; /*交談控制代碼*/
OCIStmt *stmthp; /*語句控制代碼*/
OCIDescribe *dschp; /*描述控制代碼*/
OCIError *errhp; /*錯誤控制代碼*/
OCIDefine *defhp[3]; /*定義控制代碼*/
OCIBind *bidhp[4]; /*綁定控制代碼*/
sb2 ind[3]; /*指示符變數*/
/*綁定 select 結果集的參數*/
int szpersonid; /*儲存 personid 列*/
text szname[51]; /*儲存 name 列*/
text szemail[51]; /*儲存 mail 列*/
char sql[256]; /*儲存執行的 sql 語句*/

int main(int argc, char *argv[])
{
 char strServerName[50];
 char strUserName[50];
 char strPassword[50];
 /*設定伺服器,使用者名稱和密碼*/
 strcpy(strServerName, "xxx.xxx.xxx.xxx:1521");
 strcpy(strUserName, "a****");
 strcpy(strPassword, "******");
 /*初始化 OCI 應用環境*/
 OCIInitialize(OCI_DEFAULT, NULL, NULL, NULL, NULL);
 /*初始化環境控制代碼*/
 OCIEnvInit(&envhp, OCI_DEFAULT, 0, 0);
 /*分配控制代碼*/
 OCIHandleAlloc(envhp, (dvoid **)&svchp, OCI_HTYPE_SVCCTX, 0, 0);
 /*伺服器環境控制代碼*/
 OCIHandleAlloc(envhp, (dvoid **)&srvhp, OCI_HTYPE_SERVER, 0, 0);
 /*伺服器控制代碼*/
 OCIHandleAlloc(envhp, (dvoid **)&authp, OCI_HTYPE_SESSION, 0, 0);
 /*交談控制代碼*/
 OCIHandleAlloc(envhp, (dvoid **)&errhp, OCI_HTYPE_ERROR, 0, 0);
 /*錯誤控制代碼*/
 OCIHandleAlloc(envhp, (dvoid **)&dschp, OCI_HTYPE_DESCRIBE, 0, 0);
 /*描述項控制代碼*/
 /*串連伺服器*/
 OCIServerAttach(srvhp, errhp, (text *)strServerName, (sb4)strlen(strServerName), OCI_DEFAULT);
 /*設定使用者名稱和密碼*/
 OCIAttrSet(authp, OCI_HTYPE_SESSION, (text *)strUserName, (ub4)strlen(strUserName), OCI_ATTR_USERNAME, errhp);
 OCIAttrSet(authp, OCI_HTYPE_SESSION, (text *)strPassword, (ub4)strlen(strPassword), OCI_ATTR_PASSWORD, errhp);
 /*設定伺服器環境控制代碼屬性*/
 OCIAttrSet((dvoid *)svchp, (ub4)OCI_HTYPE_SVCCTX, (dvoid *)srvhp, (ub4)0, OCI_ATTR_SERVER, errhp);
 OCIAttrSet(svchp, OCI_HTYPE_SVCCTX, (dvoid *)authp, 0, OCI_ATTR_SESSION, errhp);
 /*建立並開始一個使用者會話*/
 OCISessionBegin(svchp, errhp, authp, OCI_CRED_RDBMS, OCI_DEFAULT);
 OCIHandleAlloc(envhp, (dvoid **)&stmthp, OCI_HTYPE_STMT, 0, 0);
 /*語句控制代碼*/

 /************************************************************************/
 /*建立 person 表*/
 /************************************************************************/
 static text* SQL_CREATE_TB = (text*)"create table person(personid number, name varchar(256), email varchar(256))";
 /*準備 SQL 陳述式*/
 OCIStmtPrepare(stmthp, errhp, SQL_CREATE_TB, strlen((char *)SQL_CREATE_TB),OCI_NTV_SYNTAX, OCI_DEFAULT);
 /*執行 SQL 陳述式*/
 OCIStmtExecute(svchp, stmthp, errhp, 1, 0, 0, 0, OCI_DEFAULT);
 /*提交到資料庫*/
 OCITransCommit(svchp, errhp, OCI_DEFAULT);

 /************************************************************************/
 /*插入資料*/
 /************************************************************************/
 memset(sql, 0, sizeof(sql));
 strcpy(sql, "insert into person values(:personid,:name,:email)");
 /*準備 SQL 陳述式*/
 OCIStmtPrepare(stmthp, errhp, (text *)sql, strlen(sql),OCI_NTV_SYNTAX, OCI_DEFAULT);
 /*綁定輸入列*/
 OCIBindByName(stmthp, &bidhp[0], errhp, (const OraText*)":personid", 9, &szpersonid, sizeof(szpersonid), SQLT_INT, NULL, NULL, NULL, 0, NULL, 0);
 OCIBindByName(stmthp, &bidhp[2], errhp, (const OraText*)":name", 5, szname, sizeof(szname), SQLT_STR, NULL, NULL, NULL, 0, NULL, 0);
 OCIBindByName(stmthp, &bidhp[3], errhp, (const OraText*)":email", 6, szemail, sizeof(szemail), SQLT_STR, NULL, NULL, NULL, 0, NULL, 0);
 /*設定輸入參數*/
 szpersonid = 1;
 memset(szname, 0, sizeof(szname));
 strcpy((char*)szname, "obtest");
 memset(szemail, 0, sizeof(szemail));
 strcpy((char*)szemail, "t@ob.com");
 /*執行 SQL 陳述式*/
 OCIStmtExecute(svchp, stmthp, errhp, (ub4)1, (ub4)0, (CONST OCISnapshot *)0, (OCISnapshot *)0, (ub4)OCI_DEFAULT);
 /*提交到資料庫*/
 OCITransCommit(svchp, errhp, OCI_DEFAULT);

 /************************************************************************/
 /*查詢 person 表*/
 /************************************************************************/
 strcpy(sql, "select personid ,name,email from person;");
 /*準備 SQL 陳述式*/
 OCIStmtPrepare(stmthp, errhp, (text *)sql, strlen(sql), OCI_NTV_SYNTAX, OCI_DEFAULT);
 /*綁定輸出資料行*/
 OCIDefineByPos(stmthp, &defhp[0], errhp, 1, &szpersonid, sizeof(szpersonid), SQLT_STR, &ind[0], 0, 0, OCI_DEFAULT);
 OCIDefineByPos(stmthp, &defhp[1], errhp, 2, (ub1 *)szname, sizeof(szname), SQLT_STR, &ind[1], 0, 0, OCI_DEFAULT);
 OCIDefineByPos(stmthp, &defhp[2], errhp, 3, (ub1 *)szemail, sizeof(szemail), SQLT_STR, &ind[2], 0, 0, OCI_DEFAULT);
 /*執行 SQL 陳述式*/
 OCIStmtExecute(svchp, stmthp, errhp, (ub4)0, 0, NULL, NULL,
 OCI_DEFAULT);
 printf("%-10s%-10s%-10s\n", "PERSONID", "NAME", "email");
 while ((OCIStmtFetch(stmthp, errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT)) != OCI_NO_DATA)
 {
 printf("%-10d", szpersonid);
 printf("%-10s", szname);
 printf("%-10s\n", szemail);
 break;
 }
 /*提交到資料庫*/
 OCITransCommit(svchp, errhp, OCI_DEFAULT);

 /************************************************************************/
 /*刪除 person 表*/
 /************************************************************************/
 static text* SQL_DROP_TB = (text*)"drop table person";
 /*準備 SQL 陳述式*/
 OCIStmtPrepare(stmthp, errhp, (text*)SQL_DROP_TB, strlen((char *)SQL_DROP_TB), OCI_NTV_SYNTAX, OCI_DEFAULT);
 /*執行 SQL 陳述式*/
 OCIStmtExecute(svchp, stmthp, errhp, 1, 0, 0, 0, OCI_COMMIT_ON_SUCCESS);
 /*提交到資料庫*/
 OCITransCommit(svchp, errhp, OCI_DEFAULT);
 
 //結束會話
 OCISessionEnd(svchp, errhp, authp, (ub4)0);
 //斷開與資料庫的串連
 OCIServerDetach(srvhp, errhp, OCI_DEFAULT);
 //釋放OCI控制代碼
 OCIHandleFree((dvoid *)dschp, OCI_HTYPE_DESCRIBE);
 OCIHandleFree((dvoid *)stmthp, OCI_HTYPE_STMT);
 OCIHandleFree((dvoid *)errhp, OCI_HTYPE_ERROR);
 OCIHandleFree((dvoid *)authp, OCI_HTYPE_SESSION);
 OCIHandleFree((dvoid *)svchp, OCI_HTYPE_SVCCTX);
 OCIHandleFree((dvoid *)srvhp, OCI_HTYPE_SERVER);
 return 0;
}

修改代碼中的資料庫連接參數。參考如下欄位,對應的值,則取自步驟一擷取的資料庫連接參數。

strcpy(strServerName, "xxx.xxx.xxx.xxx:1521");
strcpy(strUserName, "a****");
strcpy(strPassword, "******");
  • strServerName:取自 -h -P 參數,OceanBase 資料庫連接的網域名稱和連接埠。Oracle 模式租戶預設連接埠是 1521。

  • strUserName:取自 -u 參數,串連租戶的帳號。

  • strPassword:取自 -p 參數,帳號密碼 。

步驟四:執行樣本

  1. 代碼編輯完成後,可以通過如下命令進行編譯。

    $ gcc test.c -I/u01/obclient/include /u01/obclient/lib/libobci.a -L/usr/local/lib64 -lstdc++ -lpthread -ldl -lm -g -o test

    如果使用了高版本 obci,安裝 Oracle Instant Client,-I 需要使用 Oracle 目錄,如下:

    $ gcc test.c -I/usr/include/oracle/21/client64/ -L/u01/obclient/lib/ -L/usr/local/lib64 -lobci -lobclnt -g  -o test
  2. 編譯完成後,指定運行路徑。

    $ export LD_LIBRARY_PATH=/u01/obclient/lib
  3. 運行程式碼範例。

    $ ./test
  4. 運行得到如下結果,說明資料庫連接成功且語句執行正常。

    PERSONID  NAME      email
    49        obtest    t@ob.com