设为首页 收藏本站
查看: 870|回复: 0

[经验分享] 使用oci封装库ocilib访问oracle

[复制链接]

尚未签到

发表于 2016-7-22 08:36:13 | 显示全部楼层 |阅读模式
讲下背景,目前项目当中使用occi的一个封装库编写dao,但这个方案并不是特别理想。
对于Oracle对待occi的态度一直不太理解,oci的api非常复杂,而对简单很多的occi Oracle支持力度却非常有限。
在Oracle安装版本当中,只提供很少的几个occi编译库。
而且occi库对编译器,编译器版本,数据库版本,crt版本,操作平台版本都有诸多限制。
尽管window上occi也提供了支持vs的链接库,但在window上并不是任何版本的vs都能支持,稍老的05都不支持10G带的的occi库。
在linux上甚至有低版本gcc支持,然后版本高点的gcc反而不支持的情况。
以前写代码本来期望window上mingw测试,unix上部署,结果发觉mingw根本没有能用的occi链接库,而在unix上都得很折腾然后才能让occi正常跑起来。
要注意的是occi支持的编译器、OS平台、各自版本都有限制,如果通过occi访问Oracle一定要确认未来的production运行和编译环境是否明确在支持列表。
采取oci访问Oracle则好很多,c库在mingw,vs都可以透明使用,而且对各个主流OS和编译器也都能很好支持,这样很容易就做到一次编写,多处运行,window下用mingw写出的代码很容易移到unix或linux的gcc甚至acc下。
但oci的缺点也很明显:api太复杂,一个简单的功能也要写大量代码。
于是出现了一些封装oci但是是以类jdbc或者occi风格的wrapper库,比如oraLib,ocilib,ocl。这里介绍一下ocilib:
ocilib封装的oci.lib,以c lib的形式提供给用户,这样使得基于它编写的代码如果今后转到其他平台和编译器上几乎没有需要改动的地方。
并且ocilib支持的数据库特性非常多,换句话说它对多数的oci api都提供了封装,并且以简洁的接口暴露给开发者。
ocilib是lgpl的license,这意味你只要不静态链接ocilib或者封装它,可以免费用到你的商业产品中(封装的话需要开源封装部分的代码)。
下面是一个简单的建立数据库连接的代码:
#include "ocilibDemo.h"
void err_handler(OCI_Error *err)
{
printf(
"code  : ORA-%05i\n"
"msg   : %s\n"
"sql   : %s\n",
OCI_ErrorGetOCICode(err),
OCI_ErrorGetString(err),
OCI_GetSql(OCI_ErrorGetStatement(err))
);
}
void conn()
{
OCI_Connection *cn;
if (!OCI_Initialize(err_handler, NULL, OCI_ENV_DEFAULT))
return;
cn = OCI_ConnectionCreate(tnsName, user, password, OCI_SESSION_DEFAULT);
if (cn != NULL) {
printf(OCI_GetVersionServer(cn));
printf("Server major    version : %i\n", OCI_GetServerMajorVersion(cn));
printf("Server minor    version : %i\n", OCI_GetServerMinorVersion(cn));
printf("Server revision version : %i\n", OCI_GetServerRevisionVersion(cn));
printf("Connection      version : %i\n", OCI_GetVersionConnection(cn));
/* ... application code here ... */
OCI_ConnectionFree(cn);
}
OCI_Cleanup();
return;
}

其中err_handler是作为异常处理函数,会在数据库error发生时被调用。
注意ocilib代码在编译时要设置宏/DOCI_API=__stdcall和/DOCI_CHARSET_XXX,XXX是具体字符集类型有三种:
-  OCI_CHARSET_ANSI     : all strings are in ANSI
-  OCI_CHARSET_UNICODE  : all strings are Unicode (versions of Oracle> = 9i)  
-  OCI_CHARSET_MIXED    : SQL statements + metadata are in ANSI, user data and resultset data in Unicode
客户端和服务器端最好都统一设置ANSI或者UNICODE,避免麻烦。
下面是些简单的dml代码:
void  createTable(){
OCI_Statement  *st = NULL;
OCI_Connection *cn;
if (!OCI_Initialize(err_handler, NULL, OCI_ENV_DEFAULT))
return;
cn = OCI_ConnectionCreate(tnsName, user, password, OCI_SESSION_DEFAULT);
if (cn!=NULL) {
st = OCI_StatementCreate(cn);
char sql[]=MT("create table test_table ")
MT("( ")
MT("val_int  number, ")
MT("val_flt  float, ")
MT("val_str  varchar2(30), ")
MT("val_date date")
MT(")");
cout<<"Create table:\n"<<sql<<endl;
OCI_ExecuteStmt(st, sql);
OCI_ConnectionFree(cn);
}
OCI_Cleanup();
}
void dropTable(){
OCI_Statement  *st = NULL;
OCI_Connection *cn;
if (!OCI_Initialize(err_handler, NULL, OCI_ENV_DEFAULT))
return;
cn = OCI_ConnectionCreate(tnsName, user, password, OCI_SESSION_DEFAULT);
if (cn!=NULL) {
st = OCI_StatementCreate(cn);
char sql[]=MT("drop table test_table");
cout<<"Drop table:\n"<<sql<<endl;
OCI_ExecuteStmt(st, sql);
OCI_ConnectionFree(cn);
}
OCI_Cleanup();
}
void insertBind(){
OCI_Date *date;
int i;
double flt;
OCI_Statement  *st = NULL;
OCI_Connection *cn;
if (!OCI_Initialize(err_handler, NULL, OCI_ENV_DEFAULT))
return;
cn = OCI_ConnectionCreate(tnsName, user, password, OCI_SESSION_DEFAULT);
if (cn!=NULL) {
st = OCI_StatementCreate(cn);
char sql[]=MT("insert into test_table ")
MT("( ")
MT("   val_int,  val_flt, val_str, val_date")
MT( ") " )
MT( "values ")
MT( "( ")
MT( "   :val_int, :val_flt, :val_str, :val_date")
MT(") ");
cout<<"Intsert table:\n"<<sql<<endl;
OCI_Prepare(st, sql);
i   = 1;
flt = 3.14;
string s="sfsdfsdfsfsdfsdfsd";
date = OCI_DateCreate(cn);
OCI_DateSysDate(date);
OCI_BindInt(st, MT(":val_int"),  &i);
OCI_BindDouble(st, MT(":val_flt"), &flt);
OCI_BindString(st, MT(":val_str"), const_cast<char *>(s.c_str()), 30);
OCI_BindDate(st, MT(":val_date"), date);
OCI_Execute(st);
OCI_DateFree(date);
OCI_Commit(cn);
OCI_ConnectionFree(cn);
}
OCI_Cleanup();
}
void insertArray(){
OCI_Connection *cn;
OCI_Statement  *st;
OCI_Error      *err;
int count=20000000;
int batchSize=5000;
int tab_int[batchSize];
double tab_flt[batchSize];
char tab_str[batchSize][31];
OCI_Date* tab_date[batchSize];
int i;
if (!OCI_Initialize(err_handler, NULL, OCI_ENV_DEFAULT))
return;
cn = OCI_ConnectionCreate(tnsName, user, password, OCI_SESSION_DEFAULT);
st = OCI_StatementCreate(cn);
OCI_Prepare(st, "insert into test_table values(:i, :f, :s, :t)");
OCI_BindArraySetSize(st, batchSize);
OCI_BindArrayOfInts(st, ":i", tab_int, 0);
OCI_BindArrayOfDoubles(st, ":f", tab_flt, 0);
OCI_BindArrayOfStrings(st, ":s", (char*) tab_str, 30, 0);
OCI_BindArrayOfDates(st,":t",tab_date,0);

for (i=0;i<batchSize;i++) {
tab_int = i+1;
tab_flt=3.14;
sprintf(tab_str,"Name %d",i+1);
tab_date = OCI_DateCreate(cn);
OCI_DateSysDate(tab_date);
}
int round=count/batchSize;
clock_t start=clock();
cout<<start<<endl;
for (int j=0;j<round;j++) {
if (!OCI_Execute(st)) {
printf("Number of DML array errors : %d\n", OCI_GetBatchErrorCount(st));      
err = OCI_GetBatchError(st);
while (err) {
printf("Error at row %d : %s\n", OCI_ErrorGetRow(err), OCI_ErrorGetString(err));      
err = OCI_GetBatchError(st);
}
}
OCI_Commit(cn);
//      printf("row processed : %d\n", OCI_GetAffectedRows(st));
}
clock_t stop=clock();
cout<<stop<<endl;
int costTime=stop-start;
double numberPerSec=(count/costTime)*1000;
cout<<"Insert records "<<count<<" cost time "<<costTime<<" ms"<<endl;
cout<<"Insert records "<<numberPerSec<<"records/s "<<endl;
for (i=0;i<batchSize;i++) {
OCI_DateFree(tab_date);
}
OCI_Commit(cn);
OCI_ConnectionFree(cn);
OCI_Cleanup();
return;
}
ocilib的代码可以跑在装有Oracle client或instant client的任何机器上,通过tns访问数据库,如果是instant client注意设置tns和home路径。
更多的例子可以查看ocilib自带的demo和文档,ocilib的demo非常完备,提供了它支持的所有特性的例子

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-247571-1-1.html 上篇帖子: 浅谈在Hibernate中使用Oracle sequence 下篇帖子: (笔记)Oracle中的批量删除数据
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表