暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

OCI编程基础篇(三) 连接到数据库

原创 tomcoding 2025-08-13
218

访问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数据库上,后面就可以进行对数据库的访问了。

是不是看完上面的内容,还是不知道怎样建立一个数据库连接?下一节我们看一个完整的程序,里面有详细的步骤和函数调用的先后顺序,看完就会完全明白的。

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论