OCI編程基礎篇(三) 連接到數據庫
訪問www.tomcoding.com網站,學習Oracle內部數據結構,詳細文檔說明,下載Oracle的exp/imp,DUL,logminer,ASM工具的源代碼,學習高技術含量的內容。
連接到數據庫的過程中要分配好幾個句柄,我們先看看連接到數據庫需要哪幾步。首先需要有一個連接數據庫的對象,接著這個對象要與數據庫服務器建立關系,然后需要創建一個會話,會話需要用戶名和密碼來認證,接下來要啟動會話,這樣就建立了一個用戶會話到數據庫的連接。到這里還沒完,還要創建一個服務上下文,把服務器對象和會話都放到上下文中,這樣在后面用戶修改數據時,才能提交事務,提交事務的函數要用到服務上下文。
分配服務器句柄
使用前面介紹的分配句柄的函數OCIHandleAlloc()分配一個服務器句柄,句柄類型為OCI_HTYPE_SERVER,父句柄還是OCI的環境句柄envhp。
sword rc;
OCIEnv *envhp;
OCIServer *svrhp
rc = OCIHandleAlloc(
(const void *)envhp,
(void **)&svrhp,
OCI_HTYPE_SERVER,
0,
(void **)NULL
);
if (rc != OCI_SUCCESS) {
fprintf(stderr, "OCIHandleAlloc() - allocate server handle error !\n");
return (-1);
}
建立到服務器的連接
分配完服務器句柄,就要用它連接到服務器,這一步用到的函數叫做OCIServerAttach(),建立一條與Oracle服務器的通信路徑。看一下函數原型和參數。
sword OCIServerAttach ( OCIServer *srvhp,
OCIError *errhp,
const OraText *dblink,
sb4 dblink_len,
ub4 mode );
srvhp是一個輸入/輸出參數,輸入的是前面分配的句柄,指向一片未初始化的內存,函數調用后,這片內存就被初始化了。不能傳入一個已經建立連接的句柄,否則會報錯。
errhp是一個輸入/輸出參數,輸入的是前面分配的出錯句柄,調用函數出錯后,輸出的句柄包含錯誤信息。
dblink是一個輸入參數,這是一個字符串,用于指示連接數據庫的信息。如果使用TNS連接數據庫,那么這兒就是TNS名稱。如果使用連接字符串,有兩種格式,一種是//ip:port/service_name,另一種就是類似TNS配置中的格式(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=ip)(PORT=port))(CONNECT_DATA=(SERVICE_NAME=service_name)))。舉例,如果Oracle服務器ip地址為192.168.10.110,端口port為1521,服務名service_name為orcl,那么第一種連接格式為//192.168.10.110:1521/orcl,第二種連接格式為(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.10.110)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=orcl)))。如果dblink賦值為NULL的話,會連接本機的Oracle服務器。
dblink_len是一個輸入參數,表示上面連接字符串的長度,如果dblink為NULL,在這里賦值為0。
mode是一個輸入參數,指定連接的模式,有兩個值,一個是OCI_DEFAULT,缺省模式,另一個是OCI_CPOOL,連接池模式。一般用缺省模式就可以了。
函數調用成功后,Oracle數據庫的后臺就會啟動一個進程,與這個連接關聯起來。看一個例子,連接到本地數據庫。
sword rc;
OCIError *errhp;
OCIServer *svrhp;
rc = OCIServerAttach(
svrhp,
errhp,
(const OraText *)NULL,
0,
OCI_DEFAULT
);
if (rc != OCI_SUCCESS) {
fprintf(stderr, "OCIServerAttach() - attach server error !\n");
return (-1);
}
開始一個會話
連接到數據庫以后,下一步就是啟動一個用戶到數據庫的會話過程,用到的函數叫做OCISessionBegin()。不過在開始會話前要先分配一個會話句柄,類型為OCI_HTYPE_SESSION,然后還要給句柄設置用戶名和密碼的屬性,這樣才能開始一個用戶會話。下面是分配會話句柄的例子。
OCIEnv *envhp;
OCISession *usrhp;
rc = OCIHandleAlloc(
(void *)envhp,
(void **)&usrhp,
OCI_HTYPE_SESSION,
0,
(void **)NULL
);
if (rc != OCI_SUCCESS) {
fprintf(stderr, "OCIHandleAlloc() - allocate session handle error !\n");
return (-1);
}
為會話句柄設置屬性,要用到一個函數叫做 OCIAttrSet(),先看一下函數原型和參數。
sword OCIAttrSet ( void *trgthndlp,
ub4 trghndltyp,
void *attributep,
ub4 size,
ub4 attrtype,
OCIError *errhp );
trgthndlp是一個輸入/輸出參數,是要設置屬性的句柄。這里就是會話句柄。
trghndltyp是一個輸入/輸出參數,是要設置屬性的句柄類型。這里是OCI_HTYPE_SESSION。
attributep是一個輸入參數,是要設置的屬性值,如果文本屬性,就指向一個字符串,如果是整數屬性,就指向一個整數的地址。
size是一個輸入參數,是要設置的屬性值的大小,大多數時候設置為0,函數可以根據屬性類型知道屬性值的大小,如果屬性是文本,那么必須輸入文本的長度。
attrtype是一個輸入參數,是要設置屬性的類型。我們要設置用戶屬性,這里的類型為OCI_ATTR_USERNAME。
errhp是一個輸入/輸出參數,是函數調用出錯后返回錯誤信息用的。
如果用戶名為hr,密碼為passwd,那么設置會話屬性的示例如下。
/* 設置用戶屬性 */
rc = OCIAttrSet(
(void *)usrhp,
OCI_HTYPE_SESSION,
(void *)"hr",
strlen("hr"),
OCI_ATTR_USERNAME,
errhp
);
if (rc != OCI_SUCCESS) {
fprintf(stderr, "Set user attribute error !\n");
return (-1);
}
/* 設置密碼屬性 */
rc = OCIAttrSet(
(void *)usrhp,
OCI_HTYPE_SESSION,
(void *)"passwd",
strlen("passwd"),
OCI_ATTR_PASSWORD,
errhp
);
if (rc != OCI_SUCCESS) {
fprintf(stderr, "Set password attribute error !\n");
return (-1);
}
下面就是開啟一個會話,先看一下OCISessionBegin()函數的原型和參數。
sword OCISessionBegin ( OCISvcCtx *svchp,
OCIError *errhp,
OCISession *usrhp,
ub4 credt,
ub4 mode );
svchp是一個輸入參數,是服務的上下文句柄,前面說過,服務器句柄svrhp與數據庫建立連接之后,要放到上下文中,這個參數就是要輸入上下文句柄。
errhp是一個輸入參數,用于返回出錯信息。
usrhp是一個輸入/輸出參數,就是前面創建的會話句柄。
credt是一個輸入參數,指定建立會話的認證類型。如果需要數據庫的用戶和密碼認證,取值為OCI_CRED_RDBMS,如果使用外部認證,取值為OCI_CRED_EXT。
mode是一個輸入參數,指定不同的操作模式,一般取值為OCI_DEFAULT就可以。
從上面看到,在調用OCISessionBegin()函數之前,需要先分配一個服務上下文句柄,并且把建立的數據庫連接服務句柄方進去,下面我們就完成這步操作。
OCISvcCtx *svchp;
OCIServer *svrhp;
sword rc;
/* 分配服務上下文句柄 */
rc = OCIHandleAlloc(
(void *)envhp,
(void **)&svchp,
OCI_HTYPE_SVCCTX,
0,
(void **)NULL
);
if (rc != OCI_SUCCESS) {
fprintf(stderr, "OCIHandleAlloc() - allocate server context error !\n");
return (-1);
}
/* 把服務器句柄放入服務上下文句柄中 */
rc = OCIAttrSet(
(void *)svchp,
OCI_HTYPE_SVCCTX,
(void *)svrhp,
0,
OCI_ATTR_SERVER,
errhp
);
if (rc != OCI_SUCCESS) {
fprintf(stderr, "Set server attribute error !\n");
return (-1);
}
現在終于可以開始會話了,然后把會話句柄加入到服務上下文句柄中。
rc = OCISessionBegin(
svchp,
errhp,
usrhp,
OCI_CRED_RDBMS,
OCI_DEFAULT
);
if (rc != OCI_SUCCESS) {
fprintf(stderr, "OCISessionBegin() - establish user session error !\n");
return (-1);
}
rc = OCIAttrSet(
(void *)svchp,
OCI_HTYPE_SVCCTX,
(void *)usrhp,
0,
OCI_ATTR_SESSION,
errhp
);
if (rc != OCI_SUCCESS) {
fprintf(stderr, "Set user session attribute error !\n");
return (-1);
}
到現在為止,我們已經連接到了Oracle數據庫上,后面就可以進行對數據庫的訪問了。
是不是看完上面的內容,還是不知道怎樣建立一個數據庫連接?下一節我們看一個完整的程序,里面有詳細的步驟和函數調用的先后順序,看完就會完全明白的。

浙公網安備 33010602011771號