连接到数据库的过程中要分配好几个句柄,我们先看看连接到数据库需要哪几步。首先需要有一个连接数据库的对象,接着这个对象要与数据库服务器建立关系,然后需要创建一个会话,会话需要用户名和密码来认证,接下来要启动会话,这样就建立了一个用户会话到数据库的连接。到这里还没完,还要创建一个服务上下文,把服务器对象和会话都放到上下文中,这样在后面用户修改数据时,才能提交事务,提交事务的函数要用到服务上下文。
分配服务器句柄
使用前面介绍的分配句柄的函数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数据库上,后面就可以进行对数据库的访问了。
是不是看完上面的内容,还是不知道怎样建立一个数据库连接?下一节我们看一个完整的程序,里面有详细的步骤和函数调用的先后顺序,看完就会完全明白的。