概述
继创建数据库连接和执行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,(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,strlen("dbp_166")); memcpy(szDBPwd,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",szDBPwd); return -1; } printf("ConnectDB success! ServiceName:%s,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,Pwd:%s)\n",iRetVal,szDBPwd); return -1; } // 调用CDbFetch函数获取数据库返回的结果 iRetVal = CDbFetch(pDBHandle,szRcvBuf,100); if (iRetVal != 0) // 执行失败 { printf("CDbFetch failed! RetVal=%d (ServiceName:%s,szDBPwd); return -1; } // 打印从数据库中获取到的结果 printf("RcvBuf=%s\n",szRcvBuf); // 调用CDbCloseDb函数关闭数据库连接 CDbCloseDb(pDBHandle); pDBHandle = NULL; // 将数据库句柄指针置为空 return 0; }
说明:
1)CDbCloseDb函数的输入参数是:数据库句柄指针,数据库句柄是由CDbCreateDb函数执行之后获得的。
2)CDbCloseDb函数执行完成之后,还要单独编写语句将数据库句柄指针置为空,防止该指针在后面的流程中被随意使用。