OTL之Oracle开发总结---转
 

关 于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 rlogon(...):这个函数有多个版本,请注意参考官方文档中与相应数据库版本对应的函数声明。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<char[20]>之类的语句,因为它们会带有输入或输出,此类SQL语句可以通过otl_stream实现,下面会有介 绍。

int ignore_error:是否忽略异常。可以指定otl_exception::disable禁用异常,否则程序需要使用try...catch(otl_exception &e)...捕获并处理异常。

int connected:此成员变量标识了连接对象是否连接成功,一旦连接成功其值即为1。即便后来网络断掉了,此值仍旧保持不变,logoff()后此值变为0。所以此变量只能用于检查rlogon是否连接成功,而不能判断当前与数据库的连接是否正常。

2. otl_stream类

void open(...):为流对象关联一个SQL语句,可以是带输入或输出的SQL语句或PL/SQL块。

const int arr_size:指定流缓冲区的大小。作为输出流使用时,若输出缓冲区中的记录数达到此值即缓冲区满时,会自动刷新缓冲区,若已设设置了自动提交则一并提交数据(默认);

const char *sqlstm:SQL语句,可以指定绑定变量,如:delete from book where id = :f1<int> and price = :f2<int>;

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<int> and price = :f2<int>, 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.rlogon("");
  outStream.open(100, "insert into book values(:f1<int>, :f2<char[50]>, :f3<int>, :f4<char[20]>)", 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, "", 0);
  outStream.open(100, "insert into book values(:f1<int>, :f2<char[50]>, :f3<int>, :f4<char[20]>)", dbConn);
  outStream.set_commit(1);
 }
}

//重新连接连接数据库函数

void ReConnect(otl_connect &otlConnect, const char *pConnStr, int iAutoCommit)
{
 if (1 == otlConnect.connected)
 {
  otlConnect.logoff();
 }

Retry:
 try
 {
  otlConnect.rlogon(pConnStr, iAutoCommit);
 }
 catch (otl_exception &e)
 {
  Sleep(1000);
  goto Retry;
 }
}

这样,调用Submit函数提交数据时,就有了网络异常处理功能,若提交失败则会一直尝试重新连接,直到连接成功为止。

本文版权归作者 kanego 和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.

最新文章

  1. hadoop分布式存储(1)-hadoop基础概念(毕业设计)
  2. CoreLocation 定位
  3. sql修改约束语法练习
  4. typedef 各类定义,各类问题大全
  5. jQuery骨架
  6. PHP获取远程图片并调整图像大小
  7. AndroidStudio工程文件导入Jar包和So第三方库
  8. asp.net中的绝对路径和相对路径
  9. P90
  10. 《C++ Primer》学习笔记 :命名空间的using声明
  11. PHP成长之路之PHP连接MySql数据库(一)
  12. Centos 7最小化安装部署PostgreSQL
  13. python 通用装饰器,带有参数的装饰器,
  14. 007 numpy数组文件的存取
  15. Pycharm 开发 Django 项目
  16. SSH管理
  17. scala 2.11.6 卸载 2.12.6 安装
  18. App.config使用方法(基础教程)
  19. spring boot 中logback多环境配置
  20. spring整合springmvc和mybatis

热门文章

  1. 使用 rman duplicate from active database 搭建dataguard 手记--系列二
  2. 百度 BAE 项目部署
  3. 请问如何突破”所选文件超出了文件的最大值设定:25.00 Mb“限制
  4. Linux C高级编程——网络编程基础(1)
  5. Unity3D总结:关于射线碰撞
  6. 使用Python处理Excel文件的一些代码示例
  7. Linux的基本使用
  8. datatables参数配置详解
  9. python的id()函数的一个小方面(转载)
  10. 在zend framework框架中try{}catch(Exception e){}的跳转问题