Oracle调用接口(OCI)源码剖析(1):创建数据库连接
概述 具体而言,OCI的C语言API包括了两个文件:db_ora_oci_ux.h和db_ora_oci_ux.c。db_ora_oci_ux.h是头文件,而所有与数据库的交互操作的实现都是在db_ora_oci_ux.c中完成的。 本文对OCI的创建数据库连接操作的源码进行简单的剖析。 OCI中建立数据库连接的源码剖析 void *CDbCreateDb(INT8 *pDbType,INT8*pServer,INT8 *pDbName,INT8 *pUser,INT8 *pPwd) { CDbRecordset *pcolbuf = NULL; OCIHDBC hdbc = NULL; CDb *hDb = NULL; if (NULL == pServer) { WriteLog("CDbCreateDb: CDbCreateDb[0] failed",NULL,NULL); return NULL; } /* 申请句柄指针空间 */ hDb = (CDb *)OsGetUB(sizeof(CDb)); if (NULL == hDb) { WriteLog("CDbCreateDb: CDbCreateDb[1] failed",NULL); return NULL; } hDb->hdbc = NULL; hDb->hRec = NULL; pthread_mutex_lock(&s_dbmutex); /* 初始化数据库连接 */ hdbc = DoDbInit((text *)pServer,(text *)pUser,(text *)pPwd); if (NULL == hdbc) { pthread_mutex_unlock(&s_dbmutex); OsRetUB((UINT8*)hDb); return NULL; } /* 创建结果集 */ pcolbuf = DoRecInit(); if (NULL == pcolbuf) { pthread_mutex_unlock(&s_dbmutex); OsRetUB((UINT8*)hDb); DoDbFree(hdbc); return NULL; } hDb->hdbc = hdbc; hDb->hRec = pcolbuf; hDb->iDbType = CDB_TYPE_ORACLE; pthread_mutex_unlock(&s_dbmutex); returnhDb; } 从该函数的代码实现中,我们可以看到: 2)申请句柄指针空间操作是由OsGetUB函数实现的,初始化数据库连接操作是由DoDbInit函数实现的,创建结果集操作是由DoRecInit函数实现的。 3)为了防止在多个流程中同时调用该函数,在初始化数据库连接之前采用了加锁操作,这保证了每一个创建数据库的操作所返回的句柄是唯一的。 4)如果初始化数据库连接操作函数DoDbInit执行失败了,程序就会执行OsRetUB函数来释放句柄指针空间(该操作与之前的申请句柄指针空间操作对应起来)。 5)如果创建结果集操作函数DoRecInit执行失败了,程序除了执行OsRetUB函数来释放句柄指针空间之外,还会执行DoDbFree函数来释放数据库连接(该操作与之前的初始化数据库连接操作对应起来)。 初始化数据库连接操作函数DoDbInit的代码如下: static void *DoDbInit(text *dblink,text*uid,text *pwd) { OCIHDBC hdbc = NULL; sword rc = (sword)0; char errBuf[200]; sb4 errcode; /* 申请所有句柄指针保存空间 */ hdbc = (OCIHDBC)OsGetUB(sizeof(t_envctx)); if (NULL == hdbc) { WriteLog("DoDbInit: OsGetUB failed",NULL,NULL); return NULL; } /* 创建OCI环境 */ if (OCIInitialize((ub4)OCI_THREADED|OCI_OBJECT,(dvoid *)0,(dvoid * (*)(dvoid *,size_t))0,dvoid*,(void (*)(dvoid *,dvoid*))0)) { WriteLog("DoDbInit: OCIInitialize fail",NULL); return NULL; } if(OCIEnvInit((OCIEnv **)&hdbc->envhp,(ub4)OCI_DEFAULT,(size_t)0,(dvoid **)0)) { WriteLog("DoDbInit: OCIEnvInit fail",NULL); return NULL; } /*申请错误句柄 */ if(OCIHandleAlloc((dvoid *)hdbc->envhp,(dvoid **)&hdbc->errhp,(ub4)OCI_HTYPE_ERROR,(dvoid **)0)) { WriteLog("DoDbInit: OCIHandleAlloc allocate errhp fail",NULL); return NULL; } /* 申请服务器句柄 */ if(OCIHandleAlloc((dvoid *)hdbc->envhp,(dvoid **)&hdbc->srvhp,(ub4)OCI_HTYPE_SERVER,(dvoid **)0)) { OCIErrorGet((dvoid *)hdbc->errhp,1,&errcode,(text*)errBuf,(ub4)sizeof(errBuf),(ub4)OCI_HTYPE_ERROR); OCIHandleFree((dvoid *)hdbc->errhp,(ub4) OCI_HTYPE_ERROR); WriteLog("DoDbInit: OCIHandleAlloc allocate srvhp fail",NULL); WriteLog(errBuf,NULL); return NULL; } /* 申请服务环境句柄 */ if(OCIHandleAlloc((dvoid *)hdbc->envhp,(dvoid **)&hdbc->svchp,(ub4)OCI_HTYPE_SVCCTX,(dvoid * *)0)) { OCIErrorGet((dvoid *)hdbc->errhp,(ub4)OCI_HTYPE_ERROR); OCIHandleFree((dvoid *)hdbc->srvhp,(ub4) OCI_HTYPE_SERVER); OCIHandleFree((dvoid *)hdbc->errhp,(ub4) OCI_HTYPE_ERROR); WriteLog("DoDbInit: OCIHandleAlloc allocate svchp fail",NULL); return NULL; } /* 连接数据库 */ if (OCIServerAttach(hdbc->srvhp,hdbc->errhp,dblink,(sb4)strlen((char*)dblink),(ub4)OCI_DEFAULT)) { /* 释放环境句柄,系统自动释放在其下所分配的所有其它句柄 */ OCIErrorGet((dvoid *)hdbc->errhp,(ub4)OCI_HTYPE_SERVER); OCIHandleFree((dvoid *)hdbc->svchp,(ub4)OCI_HTYPE_SVCCTX); OCIHandleFree((dvoid *)hdbc->errhp,(ub4)OCI_HTYPE_ERROR); OCIHandleFree((dvoid *)hdbc->envhp,(ub4)OCI_HTYPE_ENV); OsRetUB((UINT8*)hdbc); WriteLog("DoDbInit: OCIServerAttach fail",NULL); return NULL; } /* 设置服务环境的服务器属性 */ OCIAttrSet((dvoid *)hdbc->svchp,(dvoid *)hdbc->srvhp,(ub4)0,(ub4)OCI_ATTR_SERVER,hdbc->errhp); /* 申请用户会话句柄 */ OCIHandleAlloc((dvoid *)hdbc->envhp,(dvoid **)&hdbc->authp,(ub4)OCI_HTYPE_SESSION,(dvoid **)0); /* 设置会话所使用的用户帐户和密码 */ if (OCIAttrSet((dvoid *)hdbc->authp,(dvoid *)uid,(ub4)strlen((char *)uid),(ub4)OCI_ATTR_USERNAME,hdbc->errhp)) { OCIServerDetach(hdbc->srvhp,(ub4)OCI_DEFAULT); OCIHandleFree((dvoid *)hdbc->srvhp,(ub4)OCI_HTYPE_ERROR); OCIHandleFree((dvoid *)hdbc->authp,(ub4)OCI_HTYPE_SESSION); OCIHandleFree((dvoid *)hdbc->envhp,(ub4)OCI_HTYPE_ENV); OsRetUB((UINT8*)hdbc); WriteLog("DoDbInit: OCIAttrSet[OCI_ATTR_USERNAME] fail",NULL); return NULL; } if (OCIAttrSet((dvoid *)hdbc->authp,(dvoid *)pwd,(ub4)strlen((char *)pwd),(ub4)OCI_ATTR_PASSWORD,(ub4)OCI_HTYPE_ENV); OsRetUB((UINT8*)hdbc); WriteLog("DoDbInit: OCIAttrSet[OCI_ATTR_PASSWORD] fail",NULL); return NULL; } /* 建立数据库操作会话 */ if ( (rc = OCISessionBegin(hdbc->svchp,hdbc->authp,(ub4)OCI_CRED_RDBMS,(ub4)OCI_DEFAULT))) { DoDbErrProc(hdbc->errhp,rc,"OCISessionBegin"); OCIServerDetach(hdbc->srvhp,(ub4)OCI_HTYPE_ENV); OsRetUB((UINT8*)hdbc); WriteLog("DoDbInit: OCISessionBegin fail",NULL); return NULL; } /* 设置会话服务环境 */ if (OCIAttrSet((dvoid *)hdbc->svchp,(dvoid *)hdbc->authp,(ub4)OCI_ATTR_SESSION,hdbc->errhp)) { OCISessionEnd(hdbc->svchp,(ub4)0); OCIServerDetach(hdbc->srvhp,(ub4)OCI_HTYPE_ENV); OsRetUB((UINT8*)hdbc); WriteLog("DoDbInit:OCIAttrSet[OCI_ATTR_SESSION] fail",NULL); return NULL; } hdbc->stmthp = NULL; return hdbc; } 下面对DoDbInit函数进行分析: 2)实现以上十一步操作的函数均是OCI底层提供的(都以OCI打头)。不管哪一步操作执行失败,都会输出相关的日志,可供排查问题。 3)所有OCI主要句柄数据结构OCIHDBC的实现如下: /* 所有OCI主要句柄数据结构 */ typedef struct { OCIEnv *envhp; /* 环境句柄 */ OCIError *errhp; /* 错误句柄 */ OCIServer *srvhp; /* 服务器句柄 */ OCISvcCtx *svchp; /* 服务环境句柄 */ OCISession *authp; /* 会话句柄 */ OCIStmt *stmthp; /* 语句句柄 */ }t_envctx; typedef t_envctx *OCIHDBC; /* 方便使用定义OCIHDBC数据类型 */ 以上不同的操作是对OCIHDBC结构体中对应的句柄赋值。 创建结果集操作函数DoRecInit的代码如下: static CDbRecordset *DoRecInit() { CDbRecordset *hRecordset; hRecordset = (CDbRecordset *)OsGetUB(sizeof(CDbRecordset)); if (NULL == hRecordset) { WriteLog("DbInitRecordset: DbInitRecordset[0] fail",NULL); return NULL; } memset((void *)hRecordset,0,sizeof(CDbRecordset)); return hRecordset; } 下面对DoRecInit函数进行分析: (编辑:大庆站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |