`
kyg313wd
  • 浏览: 11661 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

OCI

 
阅读更多

OCI
2011年12月05日
  OCI编程的一般过程
  与OCI7.3中使用的宿主语言定义变量存储空间(很拗口,不用管它)的方式不同,OCI9以后已不再使用原有的变量结构来初始化及维护数据库的信息,而改用句柄的形式来和Oracle数据库进行交互。将常用的句柄定义在一个结构内,方便程序维护:
  ?
  1
  2
  3
  4
  5
  6
  7
  8
  9
  typedef struct _OCI_HANDLE
  {
  OCIEnv     *phEnv;        //环境句柄,要使用oracle数据库,必须首先获得环境句柄
  OCISvcCtx  *phService;    //oracle的服务句柄,也可以说是连接句柄。
  OCIError   *phErr;        //oracle的错误句柄,可以获取错误信息
  OCIStmt    *phStmt;       //oracle的语句描述句柄
  OCIServer  *phServer;     //Oracle的服务器句柄
  OCISession *phSession;    //Oracle会话句柄
  }OCIHANDLE, *LPOCIHANDLE;
  OCI9编程的一般步骤有:初始化环境句柄、生成其他各类句柄、建立数据库连接进行登录、执行SQL语句,对返回的结果进行处理、终止用户会话,断开连接,释放各种句柄。  
  
  
       上图给出OCI初始化的一个过程,OCI能初始化成功的前提当然是系统中已经安装或设置了Oracle的client端(在本文第四节有介绍)。其中步骤(3)到(7)都分别调用OCIHandleAlloc()函数进行分配,顺序可以不同,它们都只依赖环境句柄;步骤(1)和(2)可以使用OCIEnvCreate()函数替换掉,这两种的初始化OCI环境的方法在不同的使用条件下是不同的,一般建议使用OCIEnvCreate()代替OCIInitialize()和OCIEnvInit(),因为OCIInitialize()和OCIEnvInit()主要是为了backwards-compatible。而如果是编写DLL更是应该使用OCIEnvCreate()函数,user‘guide是这样说的:
  If you are writing a DLL or a shared library using OCI library then this call should definitely be used instead of OCIInitialize() and OCIEnvInit() call.
  OCI各句柄初始化完毕后,接下来就是连接数据库,如下图:
  
  
  
  数据库连接好后可以执行SQL语句:一条SQL语句在OCI应用程序中的执行步骤一般如下:(1)准备SQL语句。(2)在SQL语句中绑定需要输入到SQL语句中的变量。(3)执行SQL语句。(4)获取SQL中的输出描述。(5)定义输出变量。(6)获取数据。具体过程及过程中调用的函数如下图所示。对于SQL中的定义语句(如CREATE,DROP)和控制语句(如GRANT,REVOKE),由于没有数据的输入输出,只需要图2中第一步和第三步即可。操作语句(如INSERT,DELETE,UPDATE)则需要执行前三步。而查询语句(如SELECT)不仅可能有数据输入,而且也有数据的输出,因此需要执行六个步骤。
  
  
       OCI编程的一般过程还是很清晰的,流程图都是一条线………
  三、单次查询返回多行结果的实现
  设计的时候老大要求要像原有接口库那样一次查询返回多行,然后再在本地进行处理,以减少对数据库的访问。这本来是一个很正常的要求,但后面看了好些开源的OCI封装,发现它们的demo里都没有给出如何fetch多行……… 比如写的比较好的ocilib,demo中就没有给出(至少是以前的版本没给出,现在就不知道了),在写完这个OCI接口库大概半年后,再看ocilib的代码OCIDefineByPos()函数时,发现倒数第三第四个参数都是指针,说明可以fetch多行。进而发现ocilib可以通过OCI_SetFetchSize()函数来设置查询返回的行数。但为什么不在demo里给一个示例呢?就连该版本的文档里也没有这个函数的说明。很奇怪!没办法还是自己动手丰衣足食,使劲啃user’guide。
  需要fetch多行,首先要考虑执行select语句后,接收到数据放在什么地方?当然是放在缓冲区里了,在OCI里通过不同的变量函数绑定来告诉oracle client把从数据库取到的数据存放在什么地方。这里使用OCIDefineByPos()函数。下面以每次取100行为例给出具体步骤:
  1. 分配足够大的缓冲区m_pData = new unsigned char[m_DataLen * 100]。m_DataLen表示数据库表中每一行的长度(各个列长度之和),这样需要使用unsigned作Buffer,因为如果使用有符号char则取带时间的表会有问题。
  2. 根据各列的长度来定义各列在缓冲区中的位置:
  ?
  1
  2
  3
  4
  5
  6
  7
  8
  9
  10
  OCIDefineByPos(m_hOCI.phStmt,        //语句句柄
  &(m_vecColInfo.phdefine),//定义句柄
  m_hOCI.phErr,   
  i+1,              //列序号
  (ub1 *)(&(m_pData[pos])), //各列的位置pos等于当前列之前各列长度和乘以100
  m_vecColInfo.collen,   //对应列的长度 SQLT_STR, 
  (m_vecColInfo.indp),   //指示器,因为每次最多要取100行,所以indp应设为维数为100的数组。
  (m_vecColInfo.rlenp),  //返回数据的真实长度,这里也应把rlenp设为维数100的数组 
  0, 
  OCI_DEFAULT));
  m_vecColInfo为保存各列信息的vector。值得注意的是OCIDefineByPos()的第八和第九个参数:第八个参数是指示器参数,在OCIStmtFectch后只是所取的对应数据是否完整(0表示完整),由于要取100行,则在m_vecColInfo中每一个列元素对应的结构中都应定义indp[100]的数组。第九个参数用于返回所取数据的实际长度,因此也需要在一个列元素的结构体中定义rlenp[100]的数组。还有一个需要注意的是第四个参数里的pos,pos用于指定该列保存在Buffer中的起始位置。如下表是数据库中某表,执行select查询该表前100行后,数据在缓冲区m_pData中保存数据的形式如图4:
  CarKey
  MakeKey
  ModelKey
  ColorKey
  Year
  1
  1
  1
  2
  2003
  2
  2
  1
  3
  2005
  3
  2
  1
  2
  2005
  …….
  …….
  ……..
  ……..
  ………
  100
  2
  1
  1
  2006
  
  
       上图可以看到OCI在fetch多行时,先将第一列的100行数据放入m_pData中,然后以列为单位每次取100行放入m_pData。因此pos变量的赋值应写为:pos +=  100 * (m_vecColInfo[i-1].collen); 其中collen代表该列的长度。
  3. 获取数据:
  ?
  1
  2
  3
  4
  5
  OCIStmtFetch(m_hOCI.phStmt,
    m_hOCI.phErr,
    100,//每次取100行的数据
    OCI_FETCH_NEXT, 
    OCI_DEFAULT);
  第三个参数设置为100后,执行OCIStmtFetch完毕后数据就填充到缓冲区中。这里需要注意的是最后一个fetch,因为最后一次fetch时数据库表中往往已经不足100行,所以每次执行OCIStmtFetch()函数完毕要需要检查其返回值,当返回值为OCI_NO_DATA时使用:
  ?
  1
  2
  3
  4
  5
  6
  OCIAttrGet(m_hOCI.phStmt,
  OCI_HTYPE_STMT, 
  (dvoid *) &row_fetched, 
  (ub4 *) NULL, 
  (ub4) OCI_ATTR_ROWS_FETCHED,
  m_hOCI.phErr);
  row_fetched将返回剩下的行数,倒数第二个参数为OCI_ATTR_ROWS_FETCHED,在oci.h中是这样定义的:
  #define OCI_ATTR_ROWS_FETCHED  197 /* rows fetched in last call */
  在oci10中这里没有任何问题,但在一些较早的oci9版本中找不到OCI_ATTR_ROWS_FETCHED的定义……… 也就是说无法fetch多行?!迫不得已只能用oci10。可能ocilib在demo中没有fetch多行的示例也是出于这个考虑吧。
  四、Oracle即时客户端(instantclient)的配置
  过去使用OCI需要安装oracle的客户端,Oracle的普通客户端一般都很庞大,Windows平台下的客户端就有700M。Oracle公司在10g版本后推出了大小只有30M的InstantClient(即时客户端)作为oracle的访问客户端。不需要安装就可以访问Oracle的服务器。
  Windows平台下instantclient的配置和使用:
  下面以C:\Oracle为例介绍具体的配置过程。
  1.将instantclient的basic包及sqlplus包中所有文件解压至C:\Oracle。 
  2.配置系统的环境变量:
  • 将 C:\Oracle 添加到 PATH 中(位于其他 Oracle 目录之前)。例如,在 Windows 2000 上,依次单击“开始”->“设置”->“控制面板”->“系统”->“高级”->“环境变量”,编辑系统变量列表中的 PATH。WindowXP上,右击“我的电脑”->“高级”->“环境变量”。
  • 添加用户环境变量 TNS_ADMIN 设置为C:\Oracle。
  • 设置必要的 Oracle 全球化语言环境变量, 添加用户环境变量NLS_LANG 中文对应的字符集是 SIMPLIFIED CHINESE_CHINA.ZHS16GBK
  3. 一共设置以下三个环境变量(以解压缩目录C:\Oracle为例)环境变量名 变量值
  path C:\Oracle
  TNS_ADMIN C:\Oracle
  ORACLE_HOME C:\Oracle (可选)
  NLS_LANG SIMPLIFIED CHINESE_CHINA.ZHS16GBK
  4. tnsnames.ora和sqlnet.ora文件,这两个文件可以在所要访问的Oracle数据库服务器的$ORACLE_HOME/network/admin目录下找到,把tnsnames.ora中的服务器主机名改为ip地址即可。需更改时注意备份原来的文件。
  5. 配置完毕后进入C:\Oracle运行sqlplus.exe登陆对应的数据库测试是否设置正确。在windows下使用instantclient时,需要将instantclient的sdk包中的include和lib加到工程中。
  Unix平台下instantclient的配置和使用:
  本例中使用solaris_x86_10.2.0.2为客户端
  1. 将instantclient_solaris_x86_10.2.0.2中的basic、sqlplus和sdk解压至同一目录,用chmod将该目录下的所有文件设为可读写,比如:chmod
分享到:
评论

相关推荐

    oracle最新OCI文件最新的19.3版本oracle的OCI文件,兼容其下所有版本.zip

    oracle最新OCI文件,兼容一切版本! 本地安装的是64位的Oracle,但由于Navicat仅支持32位的,因此我们还需下载一个32位的客户端。 解决方案 下载32位客户端,配置进navicat中。 第1步:下载 最新OCI文件最新...

    oracle11g oci.dll

    Oracle 调用接口 (OCI) 是最全面、性能最高、基于原生“C”语言的 Oracle 数据库接口,它可以提供 Oracle 数据库的全部功能。OCI 为构建各种语言专用接口(如 Oracle JDBC-OCI、ODP.Net、Oracle 预编译器、Oracle ...

    Navicat for Oracle动态链接库oci.dll(包含多个版本)

    然后运行Navicat for Oracle,在菜单栏依次展开“工具”——“选项”——其他——OCI——OCI.DLL指定到刚复制过去的OCI.DLL位置。然后确定,退出Navicat再次运行并配置好连接,这样即可连接数据库。

    Navicat for Oracle动态链接库oci.dll(多版本)

    然后运行Navicat for Oracle,在菜单栏依次展开“工具”——“选项”——其他——OCI——OCI.DLL指定到刚复制过去的OCI.DLL位置。然后确定,退出Navicat for Oracle再次运行并配置好连接,这样即可连接数据库。

    数据库 OCI

    OCI

    Oracle OCI.dll

    各windows版本下的oci.dll oci_10.2.0.5.dll oci_11.1.0.7.0.dll oci_11.2.0.4.0.dll oci_12.2.0.1.0.dll oci_21.3.0.0.0.dll

    OCI.dll 解决Oracle OCI错误

    连接数据库时提示oci错误,使用这个oci.dll可以解决连接问题 11.2版

    oci 编程教程oci函数的详细介绍

    oci函数的详细介绍 和应用实例 OCI 连接过程比较复杂,除了分配设置各个基本句柄外,还要明确彼此之间的联系,大致流程如下: 创建环境句柄: OCIEnvCreate(&envhp;, …); 创建一个指定环境的错误句柄: ...

    oracle oci11g下载

    oracle oci11g 下载 用于navicat for oracle

    LINUX下安装PHP的oci8和PDO_OCI扩展包

    这个包包含在LINUX安装OCI8和PDO_OCI扩展所需要的安装包.

    C++实现的OCI操作Oracle数据库类

    C++实现的OCI操作Oracle数据库类,基于ocilib-4.3.3-windows.zip实现,OCI的资源可以直接到官网下载。 C++实现的OCI操作Oracle数据库类,基于ocilib-4.3.3-windows.zip实现,OCI的资源可以直接到官网下载。

    oci头文件及库文件

    oci头文件及库文件

    OCI_常用函数说明

    对数据库的访问是通过调用OCI库函数实现的,若将C语言作为宿主语言,那么ORACLE数据库调用其实就是C程序中的函数调用,一个含OCI调用的C程序其实就是用C语言编写的应用程序。这样的程序既具有SQL语言非过程性的优点...

    ORACLE OCI lib和头文件

    oracle oci 数据库开发 库和头文件, lib , .h , 下载

    php7.1 oci8扩展

    php7.1 oci8扩展 内含php_oci8.dll php_oci8_11g.dll php_oci8_12c.dll 实测可用

    64位 OCI.DLL

    64位OCI.DLL 64位 系统 使用 PL/SQL必用、 PYTHON CX_ORACLE 必备

    OCI例子_OCI使用例子

    OCI例子OCI使用例子,本断代码为OCI使用实例

    oracle10G和oracle11G的OCI.dll

    oracle10G和11G的OCI.dll,主要用于navicat工具;oracle10G和11G的OCI.dll,主要用于navicat工具

    oracle10g ,oci.dll

    oracle 10g 的oci dll

    oci.dll(版本:oracle 11.2.0.1)

    OCI(Oracle Call Interface) Oracle调用接口(OCI)是最全面的,高性能的,本土的非托管访问ORACLE的官方接口。

Global site tag (gtag.js) - Google Analytics