VS2013下C++调用ocilib访问oracle

来源:互联网 发布:琅琊榜飞剑进阶数据 编辑:程序博客网 时间:2024/06/11 04:19

项目中一直用MFC调ADO访问oracle
* ADO是一个COM组件,封装了对常用数据库的一般操作。
* 允许开发人员编写访问数据的代码而不用关心数据源是如何实现与访问驱动的,而只用关心到数据库的连接。
* 访问数据库的时候,关于SQL的知识不是必要的,但是特定数据库支持的SQL命令仍可以通过ADO中的命令对象(Command)来执行。
* 点我查看ADO
* 发现ADO编写的程序在(x86,64)和(xp,win7,winserver…)兼容方面不好,个人也不是很喜欢com(也许是个人水平有限–!)


因此找到一种替代工具ocilib
* ocilib是一个开源项目点我查看ocilib github
* ocilib特点如下(原汁原味官方介绍)
1. offers a rich, full featured and easy to use API
2. runs on all Oracle platforms
3. is written in pure ISO C code with native ISO C Unicode support
4. encapsulates OCI (Oracle Call Interface)
5. is the most complete available OCI wrapper


测试程序开发步骤如下

环境介绍:win7(64),vs2013,oracle11g client

配置ocilib:
1. 首先从网上下载ocilib,我使用的是3.12.1-windows版本,解压后目录如下,工程中需要使用include目录和lib[]目录,根据自己平台选择,这里使用lib[64]

这里写图片描述

  1. 配置步骤
    • 将include目录下的ocilib.h拷入到项目文件目录
    • 将lib[64]目录下的ociliba.lib拷到项目文件目录中,(注意后缀是a,原因最后解释),编码时头文件中使用预编译#pragma comment(lib, “ociliba.lib”) 导入静态库
    • 将lib[64]目录下ociliba.dll拷到发布目录debug/release下
  2. demo编码
    类OraclTools 继承 DBInterface接口,这里我定义了DBEntity类和DBInterface接口,主要是为了方便项目后续扩展其他数据库,只需给DBEntity对象设定对应参数,接口保持统一。

头文件DBTools.h

#pragma once#define  SUCC  1#define  FAIL  0#include"DBInterface.h"#include "ocilib.h"#pragma comment(lib, "ociliba.lib") class OraclTools : public DBInterface{public://overwrite    virtual int DBInitialize(DBEntity*);    virtual int DBconn(DBEntity*);    virtual void DBFreeResouce();    virtual void DBCleanEnv();public:    static void err_handler(OCI_Error *err);    //virtual void getConfig(string);    virtual int DBCheck(DBEntity*);    OCI_Connection* cn = NULL;    OCI_Statement* st = NULL;    OCI_Resultset* rs = NULL;private:};

类实现DBTools.cpp

#include <iostream>#include "DBTools.h"int OraclTools::DBCheck(DBEntity* dbEntity){    if (!("ORCL" == dbEntity->getDBType()))    {        return FAIL;    }    return SUCC;    }void OraclTools::err_handler(OCI_Error *err){    int   err_type = OCI_ErrorGetType(err);    char *err_msg = (char*)OCI_ErrorGetString(err);    printf("%s - %s\n", err_type == OCI_ERR_WARNING ? "warning" : "error", err_msg);}int OraclTools::DBInitialize(DBEntity* dbEntity){    int nRet = SUCC;    nRet = OCI_Initialize(OraclTools::err_handler, NULL, OCI_ENV_DEFAULT);    if (!nRet)    {        std::cout << "ORACLE:OCI_Initialize fail" << std::endl;        return FAIL;    }    return SUCC;}int OraclTools::DBconn(DBEntity* dbEntity){    cn = OCI_ConnectionCreate(dbEntity->getDBURL(),                            dbEntity->getUserName(),                            dbEntity->getPassWord(),                            OCI_SESSION_DEFAULT);    if (NULL == cn)    {        std::cout << "ORACLE:OCI_ConnectionCreate fail" << std::endl;        err_handler(OCI_GetLastError());        return FAIL;    }    return SUCC;}void OraclTools::DBFreeResouce(){    if (rs) OCI_ReleaseResultsets(st);    if (st)OCI_StatementFree(st);    if (cn)OCI_ConnectionFree(cn);}void OraclTools::DBCleanEnv(){    OCI_Cleanup();}

主函数mian.cpp

#include <iostream>#include "DBTools.h"#include "DBEntity.h"using namesapce std;int main(int argc, char *argv[]){    OraclTools ora;    DBEntity dbEntity;    dbEntity.setDBType("ORCL");    dbEntity.setDBURL("IP:端口/服务名");    dbEntity.setUserName("****");    dbEntity.setPassWord("****");    ora.DBInitialize(&dbEntity);    ora.DBconn(&dbEntity);    ora.st = OCI_StatementCreate(ora.cn);    if (NULL == ora.st)        {            std::cout << "OCI_StatementCreate fail" << std::endl;            ora.err_handler(OCI_GetLastError());            return FAIL;        }    if (!OCI_Prepare(ora.st, "select **,** from table where **"))        {            std::cout << "OCI_Prepare fail" << std::endl;            ora.err_handler(OCI_GetLastError());            return FAIL;        }    if (!OCI_Execute(ora.st))        {            std::cout << "OCI_Execute fail" << std::endl;            ora.err_handler(OCI_GetLastError());            return FAIL;        }    ora.rs = OCI_GetResultset(ora.st);    if (NULL == ora.rs)    {        std::cout << "OCI_GetResultset fail" << std::endl;        ora.err_handler(OCI_GetLastError());        return FAIL;    }    while (OCI_FetchNext(ora.rs))    {         std::cout << OCI_GetString(rs, 1) << "," << OCI_GetString(rs, 2) << std::endl;    }    system("pause");    return EXIT_SUCCESS;}

编译测试

这里要注意编译环境,选择添加64
这里写图片描述

执行结果如下

这里写图片描述

与plsql的结果一致

这里写图片描述


测试阶段的一些坑:

一. 如果选择64位的库文件,则编译平台也要对应设置64位,否则编译可以通过,但obj链接时会报“无法解析的外部符号”错误。

二. 在选择库文件时推荐使用ociliba.*,即后缀为a的文件,且工程中字符集设置为多字节字符集
1. 在测试过程中,我首先使用了m后缀的库文件,但是查询的结果只显示第一字符,比如“700203”,“举个栗子demo”只显示“7”,“举”,在工程选项中设为unicode字符也未解决问题
2. 使用w后缀的库文件,数据库都连不上,尴尬
3. 库文件后缀对应的字符版本a:ANSI, w:Unicode, m:Mixed
4. 以m和w后缀的文件工程中无法正确使用,应该需要做多字节转换,本工程中暂没有测试。

总结:

  1. 工程中测试了ocilib库文件的导入,数据库对象的初始化、连接、执行、释放、清除环境这几个功能。
  2. 工程只使用了最简单的sql语句查询进行测试,ocilib库很强大,提供了动态sql的功能,绑定变量可以让oracle在解析sql时大大提高效率,和jdbc的使用类似,这点在ADO似乎没有(也许是我没发现–!),还有存储过程,lob的支持等,可参考官方DOC。
  3. 测试用例中,只封装了ocilib的初始化、连接和释放操作,方便后续自定义连接池的实现,而ocilib对于数据库的操作已经很简洁(类似jdbc),除非是在特定场景下,否则项目中感觉没必要再做封装。
  4. 推荐C/C++中使用ocilib对oracle访问。

如需转载,请注明出处,欢迎指正

原创粉丝点击