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

OTL之Oracle开发总结《转》的更多相关文章

  1. Oracle开发之窗口函数 rows between unbounded preceding and current row

    目录=========================================1.窗口函数简介2.窗口函数示例-全统计3.窗口函数进阶-滚动统计(累积/均值)4.窗口函数进阶-根据时间范围统计 ...

  2. Oracle SQL Developer,Oracle 开发工具之toad、SQL Developer、PL/SQL Developer等比较

    参考: oracle 的几个开发工具比较 因Oracle几乎是中大型商业企业数据的首选,所以比较一下常用与Oracle的工具. Oracle SQL Developer 免费,一般开发使用足矣,常用. ...

  3. SQL server 与Oracle开发比较

    ●概念上区别 1.Oracle 是一种对象关系数据库管理系统(ORDBMS),而Sql server 只是关系型数据库管 理系统(RDBMS). 2.Oracle使用Internet文件系统,该系统基 ...

  4. 慕课网笔记之oracle开发利器-PL/SQL基础

    实例1--if语句 /* 慕课网Oracle数据库开发必备之PL/SQL_2-3 判断用户从键盘输入的数字 1.如何使用if语句 2.接收一个键盘的输入(字符串) */ set serveroutpu ...

  5. oracle开发so easy(一)

    如何让你的程序可以在oracle数据库和sqlserver数据库自由切换? 如何让你从跨数据库开发的不适中解脱出来? 跟我来吧,我们一起开始entity framework的开发之旅.是的,entit ...

  6. Oracle开发:创建一个用户并分配表空间和分配权限

    -- 创建一个用户并分配表空间和分配权限 -- 以sysdba登录 oracle@sha-col-oracle-2:~> sqlplus / as sysdba SQL*Plus: Releas ...

  7. Oracle开发常用函数与存储过程

    create or replace function Fuc_Get_AuthorName(RecID_In in varchar2, AdmID_In in varchar2) return var ...

  8. oracle 开发笔记“跨数据库查询复制”

    1.方法一:创建DBL(data base link) CREATE PUBLIC DATABASE LINK 数据链名称 CONNECT TO 登陆用户名 IDENTIFIED BY 密码 USIN ...

  9. MySQL和Oracle开发差异

    1)  数据类型差异 Oracle MySQL 注释 单独创建序列来实现 自动增长的数据类型 varchar2 varchar number tinyint,smallint,mediumint,in ...

随机推荐

  1. Java代理学习笔记

    代理模式 代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息.过滤消息.把消息转发给委托类,以及事后处理消息等.代理类与委托类之间通常会存在关联关 ...

  2. [c++菜鸟]《Accelerate C++》读书笔记

    第0章 开始学习C++ 1.<<的行为取决于它的操作数类型,<<会把它的右操作数的字符写到左操作数所指示的流中,他是结果就是它的左操作数. 2.std::endl是一个控制器, ...

  3. 微信公众平台SDK for node

    实现了下面特性: 1.开启开发人员模式 2.解析微信请求參数 3.验证消息来源 4.被动回复文字消息 5.被动回复图文消息 6.获取access_token 7.创建自己定义菜单 地址:wechat ...

  4. CString和string头文件

    在使用了MFC库的工程中CString可以直接使用,在没有使用MFC库的工程中加入#include <atlstr.h> 要使用STL里的string,要加入#include <st ...

  5. angular 资源路径问题

    1.templateUrl .component("noData",{ templateUrl:"components/noData.html" // 注意相对 ...

  6. C++静态库与动态库深入研究

    什么是库 库是写好的现有的,成熟的,可以复用的代码.现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常. 本质上来说库是一种可执行代码的二进制形式,可以被操 ...

  7. python(24)- 面向对象进阶

    面向对象基础知识: 1.面向对象是一种编程方式,此编程方式的实现是基于对类和对象的使用: 2.类是一个模板,模板中包装了多个‘函数’供使用(可以将多函数中公用的变量封装到对象中): 3.对象,根据模板 ...

  8. LVDS、MIPI、EDP、VGA、DVI、HDMI、DP3.0(雷电接口)

    1.LVDS 2.mipi 3.EDP:Embedded DisplayPort 4.VGA VGA接口的特性: 1)理论上能够支持2048x1536分辨率画面传输. 2)VGA由于是模拟信号传输,所 ...

  9. Basic Socket

    http://www.avajava.com/tutorials/lessons/how-do-i-make-a-socket-connection-to-a-server.html?page=1 t ...

  10. Xcode 6 IDE

    本文转载至 http://www.cocoachina.com/ios/20140823/9442.html     (via:苹果开发者中心) Xcode IDE 是 Apple 开发体验的核心.X ...