1、自学 OCI 编程这段自学 OCI 编程,感觉网上这方面的资料其实也不少,只是不是很容易找到。其实 OCI 没有想象的那么复杂,如果你想深究,那应该就只是时间问题。我在网上看到有人这么写到,对于 C+ 高手来说 OCI 编程只是简单的调用接口函数而已。我个人认为,学习 OCI 编程真的没那么难的,如果你想简单的会使用。那么接下来我就这段时间对 OCI 函数的学习及所收集的资料进行整合,用于帮助那些刚刚接触 OCI 编程的程序员,及 OCI 编程专家做以讨论及研究。当然以下贴出的程序虽然都已经在 x86_64-redhat-linux 系统, GCC 版本 4.1.1 20070105 (Red
2、 Hat 4.1.1-52) 下通过编译, OCI 每个函数的参数都有严格的类型定义,比较繁琐,下面的函数示例为了简洁说明,没有对错误进行处理,在实际应用中是应该注意的。 但有些个人结论并非正确,还请大家自己进行测验,得出正确结果后希望给予指正,在下不胜感激。一、理论:在这里不废话的解释什么是 OCI 及 OCI 简介。不过值得一提的是 OCI 程序的编译,下边就先对 OCI 程序怎么编译,编译过程中出现的问题做出详细解释。1 、在此只说 UNIX/LINUX 下 OCI 编程的配置。在 UNIX 下编译 OCI 程序需要 3 个必要条件:(1) 需要 oci.h 文件的所在目录。一般为 OR
3、ACLE 的安装目录: /10.2.0/db_1/rdbms/public/ 。(2) OCI 的静态链接库文件。静态库文件在我这是在用户目录下有个 lib 文件夹静态文件名为 ora.a ,其目录是: /user/lib 。这个静态文件的生产方式是用户目录下有个 OCI 文件夹,目录为: /user/oci ,是 ORACLE 的应用程序,直接 make 就可以生产该静态库了。 - 有待考核(3) 在编译时需要再加几个静态库 -lclntsh -lm lnsl 我想这几个应该是 ORACLE 数据库运行 OCI 程序的驱动库文件吧。如果不加则会提示你程序中所有 OCI 函数找不到其定义。另外
4、还需要加这些库文件的所在地址。(4) 另附 makefile 文件view plaincopy to clipboardprint?FLAGS = -g -m64 #编译 OCI 程序时所用到的头文件路径 INCLUDE_PATH = -I $ORACLE_HOME/rdbms/demo -I $ORACLE_HOME/rdbms/public -I $ORACLE_HOME/plsql/public -I $ORACLE_HOME/network/public -I $ORACLE_HOME/precomp/public -I . #编译 OCI 程序时所用到的静态链接库路径 LIB_PAT
5、H = -L$HOME/billing/lib -L$ORACLE_HOME/lib/ -L$ORACLE_HOME/rdbms/lib/ #编译 OCI 程序时所用到的静态链接库 LIBS =/billing/billing/lib/ora.a -lm -lnsl -lclntsh myoci:myoci.cpp g+ $FLAGS -o myoci myoci.cpp $INCLUDE_PATH $LIBS $LIB_PATH clean: rm -f ./core* myoci FLAGS = -g -m64#编译 OCI 程序时所用到的头文件路径INCLUDE_PATH = -I $O
6、RACLE_HOME/rdbms/demo -I $ORACLE_HOME/rdbms/public -I $ORACLE_HOME/plsql/public -I $ORACLE_HOME/network/public -I $ORACLE_HOME/precomp/public -I .#编译 OCI 程序时所用到的静态链接库路径LIB_PATH = -L$HOME/billing/lib -L$ORACLE_HOME/lib/ -L$ORACLE_HOME/rdbms/lib/#编译 OCI 程序时所用到的静态链接库LIBS =/billing/billing/lib/ora.a -lm
7、 -lnsl -lclntshmyoci:myoci.cppg+ $FLAGS -o myoci myoci.cpp $INCLUDE_PATH $LIBS $LIB_PATHclean:rm -f ./core* myoci注意:以上路径都是相对路径,是根据你的 ORACLE 安装目录而决定的。在此贴出只是当作参考。 Windows 下 VC+ 的配置和以上步骤差不错,把相应的所需头文件及其目录,静态文件及其链接库,添加到项目工程的配置里即可,在此不再一一指出。2 、句柄层次OCI 使用各种句柄操作数据库,环境句柄( Environment Handle )是所有句柄的父句柄。由于贴图不够详
8、细我把相应的 OCI 文档及资料已经上传到我的下载中,请下载后进行查阅。服务器句柄 ( Server Handle ) ,用户会话句柄( User Session Handle ) ,事务句柄( Transaction Handle )隶属于服务上下文句柄( Service Context Handle ) ,但都是以环境句柄为父句柄分配的。查询输出定位句柄( Define Handle )和输入输出绑定变量句柄( Bind Handle )在执行具体的 SQL 语句的时候,被隐含创建并连接到表达句柄( Statement Handle )上,当表达句柄释放时,它们也被隐含释放。所以在执行每一
9、个 sql 语句时,先分配表达句柄,执行结束后,释放表达句柄,这样做保证不发生由于定位句柄和绑定变量句柄引起的内存泄漏。3 、连接 ORACLE 数据库流程OCI 连接过程十比较复杂,除了分配设置各个基本句柄外,还要明确彼此之间的联系,大致流程如下:创建环境句柄: OCIEnvCreate(创建一个指定环境的错误句柄: OCIHandleAlloc(dvoid *)envhp, (dvoid *)创建一个指定环境的服务句柄: OCIHandleAlloc(dvoid *)envhp, (dvoid *)建立到数据源的访问路径 : OCIServerAttach(servhpp, errhpp,
10、);创建一个指定环境的服务上下文句柄: (void) OCIHandleAlloc(dvoid *)envhpp,);为指定的句柄及描述符设置特定的属性: (void) OCIAttrSet(dvoid *)svchpp,);创建一个指定环境的用户连接句柄: (void) OCIHandleAlloc(dvoid *)envhpp,);为用户连接句柄设置登录名及密码: (void) OCIAttrSet(dvoid *)usrhpp,);认证用户建立一个会话连接: OCISessionBegin(svchpp, errhpp,);创建一个句子句柄: OCIHandleAlloc(dvoid *
11、)envhpp,);s准备 SQL 语句: OCIStmtPrepare(stmthpp, errhpp,);绑定输入变量: OCIBindByPos(stmtp 绑定输出变量: OCIDefineByPos(stmthpp, 获得 SQL 语句类型: OCIAttrGet (dvoid *)stmthpp, (ub4)OCI_HTYPE_STMT,);执行 SQL 语句: OCIStmtExecute(svchpp, stmthpp,);释放一个会话: OCISessionRelease();删除到数据源的访问 : OCIServerDetach(servhpp, errhpp, OCI_D
12、EFAULT);释放句柄: OCIHandleFree(dvoid *) stmthpp, OCI_HTYPE_STMT);二、实践:我把程序贴到该文章的第二篇中,以下针对应用得以分析并进行说明。三、基本理论:1 、创建 OCI 环境即创建和初始化 OCI 工作环境,其他的 OCI 函数需要 OCI 环境才能执行。2 、需要申请的句柄类型:OCI 环境句柄: OCI_HTYPE_ENV 它定义所有 OCI 函数的环境调用环境,是其他句柄的父句柄。 ( 由 OCIEnvInit 或 OCIEnvCreate 生成 ) 。错误句柄: OCI_HTYPE_ERROR 作为一些 OCI 函数的参数,用
13、来记录这些 OCI 函数操作过程中所产生的错误,当有错误发生时,可用 COIErrorGet() 来读取错误句柄 中记录的错误信息。服务器环境句柄: OCI_HTYPE_SVCCTX 定义 OCI 调用的服务器操作环境,它包含服务器、用户会话和事务三种句柄。服务器句柄: OCI_HTYPE_SERVER 标识数据源,它转换为与服务器的物理连接。用户会话句柄: OCI_HTYPE_SESSION 定义用户角色和权限及 OCI 调用的执行环境。事务句柄: OCI_HTYPE_TRANS 定义执行 SQL 操作的事务环境,事务环境中包含用户的会话状态信息。语句句柄: OCI_HTYPE_STMT 是
14、一个标识 SQL 语句或 PL/SQL 块,以及其相关属性的环境。Bind/Define 句柄:属于语句句柄的子句柄,由 OCI 库隐式自动生成。用户不需要自己再申请, OCI 输入变量存储在 bind 句柄中,输出变量存储在定义句柄中。3 、句柄属性包括:服务器环境句柄属性: (OCI_HTYPE_SVCCTX)OCI_ATTR_SERVER 设置 / 读取服务环境的服务器环境属性OCI_ATTR_SESSION 设置 / 读取服务环境的会话认证环境属性OCI_ATTR_TRANS 设置 / 读取服务环境的事务环境属性用户会话句柄属性: (OCI_HTYPE_SESSION)OCI_ATTR
15、_USERNAME 设置会话认证所使用的用户名OCI_ATTR_PASSWORD 设置会话认证所使用的用户口令服务器句柄: (OCI_HTYPE_SEVER)OCI_ATTR_NOBLOCKING_MODE 设置 / 读取服务器连接: =TRUE 时服务器连接设置为非阻塞方式语句句柄: (OCI_HTYPE_STMT)OCI_ATTR_ROW_COUNT 只读,为当前已处理的行数,其 default=1OCI_ATTR_STMT_TYPE 读取当前 SQL 语句的类型:4 、 OCI 函数返回值:OCI_SUCCESS 函数执行成功 (=0)OCI_SUCCESS_WITH_INFO 执行成功
16、,但有诊断消息返回,可能是警告信息OCI_NO_DATA 函数执行完成,但没有其他数据OCI_ERROR 函数执行错误OCI_INVALID_HANDLE 传递给函数的参数为无效句柄,或传回的句柄无效OCI_NEED_DATA 需要应用程序提供运行时刻的数据OCI_CONTINUE 回调函数返回代码,说明回调函数需要 OCI 库恢复其正常的处理操作OCI_STILL_EXECUTING 服务环境建立在非阻塞模式, OCI 函数调用正在执行中。5 、 OCI 函数设置的模式有:OCI_DEFUALT: 使用 OCI 默认的环境OCI_THREADED :线程环境下使用 OCIOCI_OBJECT
17、 :对象模式OCI_SHARED :共享模式OCI_EVENTSOCI_NO_UCBOCI_ENV_NO_MUTEX :非互斥访问模式6 、 OCI 重定义数据类型typedef unsigned char ub1;typedef unsigned short ub2;typedef unsigned int ub4;typedef signed char sb1;typedef signed short sb2;typedef signed int sb4;typedef ub4 duword;typedef sb4 dsword;typedef dsword dword;#include
18、#include #include #include #include using namespace std;struct resultint id;char name20;char date20;result()id = 0;memset(name, 0, sizeof(name);memset(date, 0, sizeof(date);int main()/ 初始化 OCI 环境句柄指针 , 对应的句柄类型 OCI_HTYPE_ENVOCIEnv *envhpp = NULL;/ 初始化服务器句柄 , 对应的句柄类型 OCI_HTYPE_SERVEROCIServer *servhpp
19、 = NULL;/ 用于捕获 OCI 错误信息 , 对应的句柄类型 OCI_HTYPE_ERROROCIError *errhpp = NULL;/ 初始化用户连接句柄 , 对应的句柄类型 OCI_HTYPE_SESSIONOCISession *usrhpp = NULL;/ 初始化服务上下文句柄 , 对应的句柄类型 OCI_HTYPE_SVCCTXOCISvcCtx *svchpp = NULL;/ 初始化句子句柄 ( 创建一个会话 ), 对应的句柄类型 OCI_HTYPE_STMTOCIStmt *stmthpp = NULL;string sid=“orcl“;/ 创建或初始化 OCI
20、 环境 , 并设置环境句柄。sword swResult = OCIEnvCreate(if (swResult != OCI_SUCCESS exit(1);cout “Oracle environment initialization success!“ endl;/ 产生一个指定环境的错误句柄OCIHandleAlloc(dvoid *)envhpp, (dvoid *)/ 产生一个指定环境的服务句柄OCIHandleAlloc(dvoid *)envhpp, (dvoid *)/ 连接 | 断开服务器 多用户方式连接 ( 创建一个存取路径到数据源 )if (OCIServerAttac
21、h(servhpp, errhpp, (text *)sid.c_str(), strlen(sid.c_str(), 0) != OCI_SUCCESS)int errcno;char errbuf512=0;sb4 errcode;/ 返回一个错误指针和一个 OCI 错误代码OCIErrorGet(dvoid *)errhpp, (ub4)1, (text *)NULL, errcno = errcode;cout “Oracle server attach error:“ errbuf endl;OCIHandleFree(dvoid *)envhpp,OCI_HTYPE_ENV);OC
22、IHandleFree(dvoid *)servhpp,OCI_HTYPE_SERVER);OCIHandleFree(dvoid *)errhpp,OCI_HTYPE_ERROR);exit(1);cout “Oracle server attach success!“ endl;/* 连接数据库 */string user = “tzos“;string pas = “tzos“;errhpp = NULL;/ 产生一个指定环境的错误句柄(void) OCIHandleAlloc(dvoid *)envhpp, (dvoid *)/ 产生一个指定环境的服务上下文句柄(void) OCIHa
23、ndleAlloc(dvoid *)envhpp, (dvoid *)/ 为指定的句柄及描述符设置特定的属性 ( 为服务句柄指定服务上下文 )(void) OCIAttrSet(dvoid *)svchpp, OCI_HTYPE_SVCCTX, (dvoid *)servhpp, (ub4)0, OCI_ATTR_SERVER, (OCIError *)errhpp);/ 产生一个指定环境的用户连接句柄(void) OCIHandleAlloc(dvoid *)envhpp, (dvoid *)/ 为用户连接句柄设置登录名及密码(void) OCIAttrSet(dvoid *)usrhpp,
24、 (ub4)OCI_HTYPE_SESSION, (dvoid *)user.c_str(), (ub4)strlen(user.c_str(), (ub4)OCI_ATTR_USERNAME, errhpp);(void) OCIAttrSet(dvoid *)usrhpp, (ub4)OCI_HTYPE_SESSION, (dvoid *)pas.c_str(), (ub4)strlen(pas.c_str(), (ub4)OCI_ATTR_PASSWORD, errhpp);/ 认证用户再建立一个会话连接if(OCISessionBegin(svchpp, errhpp, usrhpp,
25、 OCI_CRED_RDBMS, (ub4)OCI_DEFAULT) != OCI_SUCCESS)int errcno;char errbuf512=0;sb4 errcode;/ 返回一个错误指针和一个 OCI 错误代码OCIErrorGet(dvoid *)errhpp, (ub4)1, (text *)NULL, errcno = errcode;cout “User session error:“ errbuf endl;OCIHandleFree(dvoid *)errhpp,OCI_HTYPE_ERROR);OCIHandleFree(dvoid *)usrhpp,OCI_HTY
26、PE_SESSION);OCIHandleFree(dvoid *)svchpp,OCI_HTYPE_SVCCTX);exit(1); cout “user session success!“ endl;(void) OCIAttrSet(dvoid *)svchpp, (ub4) OCI_HTYPE_SVCCTX, (dvoid *)usrhpp, (ub4)0, (ub4)OCI_ATTR_SESSION, errhpp);/* 执行 SQL 语句 */errhpp = NULL;/ 创建一个句子句柄if (OCIHandleAlloc(dvoid *)envhpp, (dvoid *)e
27、xit(1);cout “Create stmt success !“ endl;/ 产生一个指定环境的错误句柄/ ? 为什么如果不加这句就会出现指定 SQL 语句时就会出现错误呢?OCIHandleAlloc(dvoid *)envhpp, (dvoid *)/ 指定会话的 SQL 执行语句char sql255 = 0;sprintf(sql, “%s“, “SELECT ID,NAME,to_char(DATE, yyyy-mm-dd hh24:MI:SS) as DATE FROM STUDENT “);if (OCIStmtPrepare(stmthpp, errhpp, (text
28、 *)sql, (ub4)strlen(sql), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT) != OCI_SUCCESS)cout “Create prepare error!“ sql endl;exit(1);cout “Create prepare success!“ endl;/* 绑定参数 */ 申请绑定字段的句柄OCIDefine *bhp1 = NULL;OCIDefine *bhp2 = NULL;OCIDefine *bhp3 = NULL;OCIDefine *bhp4 = NULL;OCIDefine *bhp5 = NULL;OCI
29、Define *bhp6 = NULL;OCIDefine *bhp7 = NULL;OCIDefine *bhp8 = NULL;struct result gather;/ 指定提取数据长度ub2 datalen = 0;/ 定义指示器变量 , 用于取可能存在空值的字段char isnul6 = 0;/ 定义输出变量 ,OCIDefineByPos(stmthpp, OCIDefineByPos(stmthpp, OCIDefineByPos(stmthpp, / 获得 SQL 语句类型 , 判断会话执行的 SQL 语句时什么类型,值为 OCI_STMT_XXX 类常量ub2 stmt_t
30、ype;OCIAttrGet (dvoid *)stmthpp, (ub4)OCI_HTYPE_STMT, (dvoid *)/ 执行 SQL 语句OCIStmtExecute(svchpp, stmthpp, errhpp, (ub4)(stmt_type=OCI_STMT_SELECT?1:0), (ub4)0, (OCISnapshot *)NULL, (OCISnapshot *)NULL, OCI_DEFAULT);/ 提取信息int rows_fetched;docerr gather. id “,“;cerr gather.name “,“;cerr gather.date “.
31、 “;memset(gather.end, 0, sizeof(gather.date);while(OCIStmtFetch2(stmthpp, errhpp, 1, OCI_FETCH_NEXT, 1, OCI_DEFAULT) != OCI_NO_DATA);/ 获得记录条数OCIAttrGet(CONST void *)stmthpp, OCI_HTYPE_STMT, (void *)cout “ 总共记录数 :“ rows_fetched endl;OCILogoff(svchpp, errhpp);OCIServerDetach(servhpp, errhpp, OCI_DEFAU
32、LT);OCIHandleFree(dvoid *) stmthpp, OCI_HTYPE_STMT);OCIHandleFree(dvoid *) svchpp, OCI_HTYPE_SVCCTX);OCIHandleFree(dvoid *) servhpp, OCI_HTYPE_SERVER);OCIHandleFree(dvoid *) errhpp, OCI_HTYPE_ERROR);return 0; OCI 基本编程流程如图所示:OCI 基本编程流程1,创建和初始化 OCI 环境。OCI 环境即 OCI 函数的工作环境,在调用其他函数之前必须先调用 OCIInitialize()
33、和 OCIEnvInit()函数创建和初始化 OCI 环境,其他 OCI 函数要在这个环境中才能执行。swordOCIEnvInit(OCIEnv*envhpp,ub4mode,size_txtramemsz,dvoid*usrmempp);参数:envhp:环境句柄的指针mode:初始化模式,OCI_DEFAULT,OCI_THREADED 等xtramemsz:在应用程序中需要分配的内存的大小usrmempp:返回指向刚分配的用户内存的指针2,申请句柄句柄是指向 OCI 库所分配的内存区域的指针,该内存区域中的数据由 OCI 库维护,应用程序可通过句柄访问其中的数据。一个句柄可以用来存放上下文或连接信息(如环境或服务上下文句柄).它是由链接
Copyright © 2018-2021 Wenke99.com All rights reserved
工信部备案号:浙ICP备20026746号-2
公安局备案号:浙公网安备33038302330469号
本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。