Oracle调用接口(OCI)源码剖析(3):关闭数据库连接

概述
继创建数据库连接和执行SQL语句并获取结果之后,我们继续对OCI中关闭数据库连接的源码进行剖析。该操作主要是由CDbCloseDb函数完成的。

下面对这个函数的源码进行分析。

OCI中执行关闭数据库连接的源码剖析
在OCI中,CDbCloseDb函数的代码如下:

void CDbCloseDb(void *hDb)
{
    CDb *pCDb = NULL;

    if (NULL == hDb)
    {
        return;
    }
    pCDb = (CDb *)hDb;

   DoDbFree(pCDb->hdbc);
   DoRecFree(pCDb->hRec);
   OsRetUB((UINT8*)hDb);
   return;
}

从该函数的代码实现中,我们可以看到:
1)该函数的输入参数只有一个:数据库连接句柄。同时,该函数还调用了三个函数,DoDbFree用于释放数据库连接,DoRecFree用于释放数据库结果集行数据缓冲区,OsRetUB用于释放操作系统的数据库内存。

2)CDb结构体用于存放数据库连接句柄数据,其声明如下:

typedef struct CDbTag
{
    INT32         iDbType;  /* 数据库类型 0:sqlservr1:sybase 2:oracle*/
    OCIHDBC       hdbc;     /* 全局OCI句柄 */
    CDbRecordset *hRec;     /* 行结果集数据结构指针 */
}CDb;

释放数据库连接的DoDbFree函数的代码如下:

static void DoDbFree(OCIHDBC hdbc)
{
   if (NULL == hdbc)
   {
       return;
   }
   OCISessionEnd(hdbc->svchp, hdbc->errhp, hdbc->authp, (ub4)0);
   OCIServerDetach(hdbc->srvhp, hdbc->errhp, (ub4)OCI_DEFAULT);

   OCIHandleFree((dvoid *)hdbc->srvhp, (ub4)OCI_HTYPE_SERVER);
   OCIHandleFree((dvoid *)hdbc->svchp, (ub4)OCI_HTYPE_SVCCTX);
   OCIHandleFree((dvoid *)hdbc->errhp, (ub4)OCI_HTYPE_ERROR);
   OCIHandleFree((dvoid *)hdbc->authp, (ub4)OCI_HTYPE_SESSION);
   OCIHandleFree((dvoid *)hdbc->envhp, (ub4)OCI_HTYPE_ENV);

   OsRetUB((UINT8*)hdbc);
   hdbc = NULL;
}

从该函数的代码实现中,我们可以看到:
1)该函数调用OCI底层的函数来分别释放与数据库相关的句柄,这些句柄定义在OCIHDBC结构体中。

2)OCIHDBC结构体的声明如下:

/* 所有OCI主要句柄数据结构 */
typedef struct
{
    OCIEnv        *envhp;              /* 环境句柄 */
    OCIError      *errhp;              /* 错误句柄 */
    OCIServer     *srvhp;              /* 服务器句柄 */
    OCISvcCtx     *svchp;              /* 服务环境句柄 */
    OCISession    *authp;              /* 会话句柄 */
    OCIStmt       *stmthp;             /* 语句句柄 */
}t_envctx;
typedef t_envctx *OCIHDBC;

释放数据库结果集行数据缓冲区的DoRecFree函数的代码如下:

static void DoRecFree(CDbRecordset*hRecordset)
{
   if (NULL != hRecordset)
   {
       OsRetUB((UINT8*)hRecordset);
   }
}

从该函数的代码实现中,我们可以看到:
1)该函数调用OsRetUB函数来释放数据缓冲区。

2)结果集行数据结构体的声明如下:

typedef struct CDbRecordsetTag
{
    void          *cmd;                            /* 命令缓冲区 */
    int            sqltype;                          /* 1:select 2:other*/
    int            colCount;                         /* 返回列数 */
    char           colfieldname[CDB_MAX_COL_NUM][40];/*每列列名 */
    int            colfieldlength[CDB_MAX_COL_NUM]; /* 列名宽度 */
    int            pColWidth[CDB_MAX_COL_NUM];    /* 每列宽度 */
    int            pColType[CDB_MAX_COL_NUM];     /* 列类型 */
    char           pRecordBuf[CDB_MAX_COL_NUM][CDB_MAX_COL_WIDTH];/* 列数据 */
    int            pRetColWidth[CDB_MAX_COL_NUM];
    short          pRetIndicator[CDB_MAX_COL_NUM];
} CDbRecordset;

关闭数据库连接CDbCloseDb函数调用
当我们获取到了数据库的返回结果之后,如果不再需要使用数据库了,那么就要调用CDbCloseDb函数关闭数据库连接。

CDbCloseDb函数调用的示例代码如下:

INT32 main(void)
{
   INT8  szDBServerName[50] = {0};
   INT8  szDBName[50]       = {0};
   INT8  szDBUser[50]       = {0};
   INT8  szDBPwd[50]        = {0};
   INT8  szSqlBuf[100]      = {0};
   INT8  szRcvBuf[100]      = {0};

   INT32 iRetVal            = 0;

   void *pDBHandle          = NULL;

   // 获取数据库各参数的值
   memcpy(szDBServerName, "db192_1_8_13",strlen("db192_1_8_13"));
   memcpy(szDBName,      "dbp_166",     strlen("dbp_166"));
   memcpy(szDBUser,      "dbp_166",     strlen("dbp_166"));
   memcpy(szDBPwd,       "dbp_166",     strlen("dbp_166"));

   // 连接数据库
   pDBHandle = CDbCreateDb("Oracle", szDBServerName, szDBName, szDBUser,szDBPwd);

   if (pDBHandle == NULL)    // 连接失败
   {
       printf("ConnectDB failed! ServiceName:%s, DBName:%s, User:%s,Pwd:%s\n", szDBServerName, szDBName, szDBUser, szDBPwd);

       return -1;
   }

   printf("ConnectDB success! ServiceName:%s, DBName:%s, User:%s,Pwd:%s\n", szDBServerName, szDBName, szDBUser, szDBPwd);

   // 执行SQL语句并获取结果
   // 获取SQL语句
   memcpy(szSqlBuf, "select boxnumber from tb_test where id=1",strlen("select boxnumber from tb_test where id=1"));

   // 调用CDbExecSql函数执行SQL语句
   iRetVal = CDbExecSql(pDBHandle, szSqlBuf);
   if (iRetVal != 0)    // 执行失败
   {
       printf("CDbExecSql failed! RetVal=%d (ServiceName:%s, DBName:%s,User:%s, Pwd:%s)\n", iRetVal, szDBServerName, szDBName, szDBUser, szDBPwd);

       return -1;
   }

   // 调用CDbFetch函数获取数据库返回的结果
   iRetVal = CDbFetch(pDBHandle, szRcvBuf, 100);
   if (iRetVal != 0)    // 执行失败
   {
       printf("CDbFetch failed! RetVal=%d (ServiceName:%s, DBName:%s,User:%s, Pwd:%s)\n", iRetVal, szDBServerName, szDBName, szDBUser,szDBPwd);

       return -1;
   }

   // 打印从数据库中获取到的结果
   printf("RcvBuf=%s\n", szRcvBuf);

   // 调用CDbCloseDb函数关闭数据库连接
   CDbCloseDb(pDBHandle);
   pDBHandle = NULL;      // 将数据库句柄指针置为空

   return 0;
}

说明:
1)CDbCloseDb函数的输入参数是:数据库句柄指针,数据库句柄是由CDbCreateDb函数执行之后获得的。

2)CDbCloseDb函数执行完成之后,还要单独编写语句将数据库句柄指针置为空,防止该指针在后面的流程中被随意使用。

时间: 2024-11-23 18:17:55

Oracle调用接口(OCI)源码剖析(3):关闭数据库连接的相关文章

Oracle调用接口(OCI)源码剖析(2):执行SQL语句并获取结果

概述 接着上一篇文章<Oracle调用接口(OCI)源码剖析(1):创建数据库连接>,我们继续对OCI中执行SQL语句并获取结果的源码进行剖析.该操作主要是由两个函数完成的:CDbExecSql和CDbFetch,其中CDbExecSql函数用于执行普通SQL语句,CDbFetch函数用于获取数据库的返回结果. 下面对这两个函数的源码进行分析. OCI中执行SQL语句并获取结果的源码剖析 1.执行普通SQL语句的操作 在OCI中,执行普通SQL语句的操作是由CDbExecSql函数实现的,其代

Oracle调用接口(OCI)源码剖析(1):创建数据库连接

概述 在笔者所开发过的产品中,有很多都需要与Oracle数据库打交道.为了实现C代码与Oracle数据库的消息交互,Oracle公司为广大的开发者们提供了一个统一的调用接口OCI(Oracle Call Interface).只要按照规范来调用OCI中的函数,就能够实现C代码与Oracle数据库的交互. 具体而言,OCI的C语言API包括了两个文件:db_ora_oci_ux.h和db_ora_oci_ux.c.db_ora_oci_ux.h是头文件,而所有与数据库的交互操作的实现都是在db_o

ORACLE调用接口(OCI)简介及重要函数流程介绍

[文章摘要] 对于实现用户开销户的程序来说,与数据库进行交互是必不可少的.为了实现用户数据的存放.读取.删除等操作,我们需要频繁地访问数据库,这就对数据库的访问模式提出了较高的要求.ORACLE数据库具有系统可移植性好.使用方便.功能强等特点,因此在实际的软件开发项目中使用得非常的广泛.为了方便C语言程序操作ORACLE中的数据,ORACLE调用接口(OCI)应运而生. 本文首先简单介绍了OCI的基本情况,然后对OCI中两个重要的程序流程进行了一定的介绍.希望大家通过此文,能够对OCI有一个大致

《GDAL源码剖析与开发指南》一一1.9 简单的调用

1.9 简单的调用 GDAL源码剖析与开发指南关于GDAL的使用,关键是要熟悉GDAL的组织结构.类以及类的函数等.最常用的就是动态库的GDAL,当然我们也可以使用静态库,这里只是简单地介绍使用动态GDAL库来做开发. 下面我们简单地使用C++.C#.Python和Java 4种语言分别进行示例,来说明如何使用GDAL进行开发. 1.9.1 C ++使用GDAL首先我们打开Visual Studio2008,新建一个Win32的控制台工程(名字叫GDALCppTest),然后在工程的属性对话框中

Java集合源码剖析:TreeMap源码剖析

前言 本文不打算延续前几篇的风格(对所有的源码加入注释),因为要理解透TreeMap的所有源码,对博主来说,确实需要耗费大量的时间和经历,目前看来不大可能有这么多时间的投入,故这里意在通过于阅读源码对TreeMap有个宏观上的把握,并就其中一些方法的实现做比较深入的分析. 红黑树简介 TreeMap是基于红黑树实现的,这里只对红黑树做个简单的介绍,红黑树是一种特殊的二叉排序树,关于二叉排序树,参见:http://blog.csdn.net/ns_code/article/details/1982

Java集合源码剖析:Hashtable源码剖析

Hashtable简介 Hashtable同样是基于哈希表实现的,同样每个元素是一个key-value对,其内部也是通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长. Hashtable也是JDK1.0引入的类,是线程安全的,能用于多线程环境中. Hashtable同样实现了Serializable接口,它支持序列化,实现了Cloneable接口,能被克隆. HashTable源码剖析 Hashtable的源码的很多实现都与HashMap差不多,源码如下(加入了比较详细的注释):

Java集合源码剖析:HashMap源码剖析

HashMap简介 HashMap是基于哈希表实现的,每一个元素是一个key-value对,其内部通过单链表解决冲突问题,容量不足(超过了阀值)时,同样会自动增长. HashMap是非线程安全的,只是用于单线程环境下,多线程环境下可以采用concurrent并发包下的concurrentHashMap. HashMap 实现了Serializable接口,因此它支持序列化,实现了Cloneable接口,能被克隆. HashMap源码剖析 HashMap的源码如下(加入了比较详细的注释): pac

Java集合源码剖析:Vector源码剖析

Vector简介 Vector也是基于数组实现的,是一个动态数组,其容量能自动增长. LinkedList是JDK1.0引入了,它的很多实现方法都加入了同步语句,因此是线程安全的(其实也只是相对安全,有些时候还是要加入同步语句来保证线程的安全),可以用于多线程环境. LinkedList没有丝线Serializable接口,因此它不支持序列化,实现了Cloneable接口,能被克隆,实现了RandomAccess接口,支持快速随机访问. Vector源码剖析 Vector的源码如下(加入了比较详

JS魔法堂:mmDeferred源码剖析

一.前言   avalon.js的影响力愈发强劲,而作为子模块之一的mmDeferred必然成为异步调用模式学习之旅的又一站呢!本文将记录我对mmDeferred的认识,若有纰漏请各位指正,谢谢.项目请见:mmDeferred@github   二.API说明    {Deferred} Deferred({Function|Object} mixin?) ,创建一个Deferred实例,当mixin的类型为Object时,将mixin的属性和函数附加到Deferred实例的Promise实例上