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

连接到数据库的过程中要分配好几个句柄,我们先看看连接到数据库需要哪几步。首先需要有一个连接数据库的对象,接着这个对象要与数据库服务器建立关系,然后需要创建一个会话,会话需要用户名和密码来认证,接下来要启动会话,这样就建立了一个用户会话到数据库的连接。到这里还没完,还要创建一个服务上下文,把服务器对象和会话都放到上下文中,这样在后面用户修改数据时,才能提交事务,提交事务的函数要用到服务上下文。

分配服务器句柄

使用前面介绍的分配句柄的函数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数据库上,后面就可以进行对数据库的访问了。

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

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
oci函数的详细介绍 和应用实例 OCI 连接过程比较复杂,除了分配设置各个基本句柄外,还要明确彼此之间的联系,大致流程如下: 创建环境句柄: OCIEnvCreate(&envhp;, …); 创建一个指定环境的错误句柄: OCIHandleAlloc((dvoid *)envhp, (dvoid **)&errhp;,…); 创建一个指定环境的服务器句柄: OCIHandleAlloc((dvoid *)envhp, (dvoid **)&servhp;,…); 建立到数据源的访问路径 : OCIServerAttach(servhpp, errhpp,…); 创建一个指定环境的服务上下文句柄: (void) OCIHandleAlloc((dvoid *)envhpp,…); 为指定的句柄及描述符设置特定的属性: (void) OCIAttrSet((dvoid *)svchpp,…); 创建一个指定环境的用户连接句柄: (void) OCIHandleAlloc((dvoid *)envhpp,…); 为用户连接句柄设置登录名及密码: (void) OCIAttrSet((dvoid *)usrhpp,…); 认证用户建立一个会话连接OCISessionBegin(svchpp, errhpp,…); 创建一个句子句柄: OCIHandleAlloc((dvoid *)envhpp,…);s 准备 SQL 语句: OCIStmtPrepare(stmthpp, errhpp,…); 绑定输入变量: OCIBindByPos(stmtp &hBind;, errhp,…); 绑定输出变量: OCIDefineByPos(stmthpp, &bhp1;, errhpp,…); 获得 SQL 语句类型: OCIAttrGet ((dvoid *)stmthpp, (ub4)OCI_HTYPE_STMT,…); 执行 SQL 语句: OCIStmtExecute(svchpp, stmthpp,…); 释放一个会话: OCISessionEnd(); 删除到数据源的访问 : OCIServerDetach(servhpp, errhpp, OCI_DEFAULT); 释放句柄: OCIHandleFree((dvoid *) stmthpp, OCI_HTYPE_STMT);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值