关于OTL,网上介绍的也不少,但看来看去也只是官方的那些文档。OTL很好用,结合官方提供的一些例子,多多尝试才能领悟。经过一个月左右的项目开发,对OTL也有些了解,在这里总结一下,希望对刚接触OTL的新手有所帮助。其中有些地方,比如对网络异常的处理,可是费了我两天的时间才
解决的,我那个汗哪。废话少说,开始正题: 一、开始前的准备工作 在使用OTL进行编程之前,要首先确定使用的Oralce版本以及所选用的字符集。OTL
支持目前几乎所有的主流
数据库,可以通过宏启用otlv4.h中对应的
数据库操作接口。 如:使用Oracle 11g R2、字符集选择UTF8,则可在包含otlv4.h之前声明以下两个宏: #define OTL_ORA11G_R2 #define OTL_ORA_UTF8 #include "otlv4.h" .... 二、常用类及其常用成员 1. otl_connect类 static int otl_initialize(const int threaded_mode=0): 用于初始化OTL环境的静态
函数,参数指定是用于多线程还是单线程。它不保证线程安全,也就是说,如果多个线程共享使用一个otl_connect对象,需要加锁进行控制。有个同事因为在多线程环境下使用了默认的参数0,就导致了
程序异常。但是单线程环境下,参数设1是没有问题的。所以,可以考虑将此参数直接设为1。 void r
logon(...): 这个
函数有多个版本,请注意参考官方文档中与相应
数据库版本对应的
函数声明。11g中用到的参数说明如下: const char *connect_str:连接字符串,格式为:"
用户名/密码@
数据库服务名" const int aauto_commit:
自动提交模式。若此参数设为0(默认),则通过此连接对象执行的事务不会
自动提交。如使用direct_exec执行
删除记录的操作时,需要手动
调用commit()成员
函数提交事务;若设为1则通过此otl_connect对象开启的事务会
自动提交。 long direct_exec(...): const char *
sqlstm: 指定所要执行的“静态
sql语句”,即不产生输入或
输出的
sql语句。如delete from book where name='c++‘ 。但是不能执行如select sysdate from dual或select * from book亦或delete from book where name=:f1之类的语句,因为它们会带有输入或
输出,此类
sql语句可以通过otl_stream实现,下面会有介绍。 int ignore_error:是否忽略异常。可以指定otl_exception::disable禁用异常,否则程序需要使用try...catch(otl_exception &e)...捕获并处理异常。 int connected: 此成员变量标识了连接对象是否连接成功,一旦连接成功其值即为1。即便后来网络断掉了,此值仍旧保持不变,
logoff()后此值变为0。所以此变量只能用于检查r
logon是否连接成功,而不能判断当前与
数据库的连接是否正常。 2. otl_stream类 void open(...): 为流对象关联一个
sql语句,可以是带输入或
输出的
sql语句或PL/
sql块。 const int arr_size:指定流缓冲区的大小。作为
输出流使用时,若
输出缓冲区中的记录数达到此值即缓冲区满时,会
自动刷新缓冲区,若已设设置了
自动提交则一并提交数据(默认); const char *
sqlstm:
sql语句,可以指定绑定变量,如:delete from book where id = :f1 and price = :f2; otl_connect &db:流所使用的
数据库连接对象。 void set_commit(int auto_commit=0): 设置流被刷新时否
自动提交事务。两种条件下流会被刷新:a.缓冲区满 b.手动
调用flush成员
函数 void flush(...): 执行和流关联的
sql语句。如执行: otl_stream delStream; delStream.open(100,delete from book where id = :f1 and price = :f2,dbConnect); //正常情况下向流中加入100条记录时才执行
删除 delStream << 1; delSteam << 'C++'; delStream.flush(); //立即执行
删除操作,尽管当前流中只有一条记录 long get_rpc():
获取流中
sql语句执行后所影响到的记录数,如插入100条记录,则
调用此
函数返回的即为100 int good(): 判断流对象是否已正常打开,已打开返回1。注意:若复用一个流对象时,必须先
调用close
函数将其
关闭,然后再
调用open重新打开。 int get_dirty_buf_len():
获取当前流对象缓冲区中的记录数,其最大值为缓冲区size-1。每当缓冲区满时会
自动刷新,刷新后再
调用此
函数时返回0 3.otl_exception类 该类的几个成员用于表示异常的信息,如: char stm_text[2048]:出错的
sql语句; char var_info[256]:若在流中使用了与实际类型不符的绑定变量,此数组的值为绑定变量的信息; unsigned char msg[1000]:这个我比较喜欢用,此数组
显示出具体的异常信息(
包括oracle返回的
错误码),如连接超时等等。 三、对于网络异常的处理 现在项目对于程序的异常处理能力要求越来越高,比如网络中断或
数据库出现异常等,要求在故障恢复后,程序能正常与
数据库保持连接,使业务尽可能的少受影响。可以通过以下
方法解决此种情况。这也是折磨了我两天的一个问题:( 首先,程序要在提交数据的地方使用try...catch捕获otl_exception异常,当提交失败时,otl会抛出此异常并携带异常信息; 其次,要在捕获到异常之后,
关闭之前的连接对象(如果有流使用此连接对象,则一定要先
关闭流对象,然后再断开otl_connect对象); 最后,重新连接
数据库并再次初始化流对象。 如: void ReConnect(otl_connect &otlConnect,const char *pConnStr,int iAutoCommit); .... //声明otl对象并初始化对象 otl_connect dbConn; otl_stream outStream; void Init(void) { try { otl_connect::otl_initialize(1); dbConn.r
logon("test1/password@testdb"); outStream.open(100,"insert into book values(:f1,:f2,:f3,:f4)",dbConn); outStream.set_commit(1); } catch (otl_exception &e) { //处理异常 } } //提交数据的
函数 void Submit(void) { try { for (int i = 0; i < 5000; i++) { outStream << i; outStream << "abc"; outStream << i; outStream << "null"; } } catch(otl_exception &e) { //提交数据异常,重新连接
数据库并重新初始化流对象 outStream.close(); //必须先
关闭流对象。若先断开连接会出现
关闭流对象时报OCIHandleFree异常导致流对象无法正常
关闭引起内存泄漏 ReConnect(dbConn,"test1/password@testdb",0); outStream.open(100,dbConn); outStream.set_commit(1); } } //重新连接连接
数据库函数 void ReConnect(otl_connect &otlConnect,int iAutoCommit) { if (1 == otlConnect.connected) { otlConnect.
logoff(); } Retry: try { otlConnect.r
logon(pConnStr,iAutoCommit); } catch (otl_exception &e) { Sleep(1000); goto Retry; } } 这样,
调用Submit
函数提交数据时,就有了网络异常处理
功能,若提交失败则会一直尝试重新连接,直到连接成功为止。 另外,我写了个小小的例子,有兴趣的可以参考下:http://www.linuxidc.com/Linux/2011-10/45351.htm