OTL編程技術

什麼是OTL:OTL 是 Oracle, Odbc and DB2-CLI TemplateLibrary 的縮寫,是一個操控關係數據庫的C++模板庫,它目前幾乎支持所有的當前各種主流數據庫。

Oracle和DB2也可以由OTL間接使用ODBC的方式來進行操縱。

OTL中直接操作Oracle主要是通過Oracle提供的OCI接口進行,依賴於Oracle客戶端。

OTL使用簡單, 只要頭文件中包含有: #include “otlv4.h” 就可,實際上整個OTL就一個“.H”的文件,使用起來極爲的方便。

優點

(1).跨平臺

(2).運行效率高,與C語言直接調用數據庫API相當

(3).開發效率高,使用方便,繁在其內,簡在其外,比

     ADO.net使用起來更簡單,更簡潔

(4).部署容易,不需要ADO組件,不需要.net

     framework 等

缺點

(1).只能在C++中使用

  • OTL的主要類

主要類包括:otl_stream、otl_connect、otl_exception

•otl_stream類

    otl_stream類是OTL“流”的概念的具體表現形式,任何通過輸入/輸出參數使用SQL語句、PL/SQL 塊或者是存儲過程調用,在C++的編程中都能通過otl_stream類來實現。

        其構造函數爲:

   (1)for Oracle 7/8/9/10:

   otl_stream(const int arr_size, // 流的緩存大小

                      const char* sqlstm, // SQL語句或PL/SQL塊或存儲過程                    

                      otl_connect& db, // OTL數據庫連接對象

                       const char* ref_cur_placeholder=0, // 遊標引用佔位符名稱   

                       const char* sqlstm_label=0 // SQL 語句標籤);

(2)forODBC/DB2-CLI:

  otl_stream(const int arr_size,// 流的緩存大小

           constchar* sqlstm,// SQL語句或PL/SQL塊或存儲過程                   

           otl_connect& db,// OTL數據庫連接對象

            const int implicit_select=otl_explicit_select ,

            const char* sqlstm_label=0//SQL 語句標籤);

  OTL流構造函數,負責創建otl_stream對象並調用open()(解析sql語句)方法。

  otl_stream的性能主要被緩衝區大小arr_size一個參數控制。緩衝區大小定義了插入表的邏輯行以及與數據庫一次往反交互(one round-trip to the database)過程中從表或視圖中查詢的邏輯行。

(3)void set_commit(int auto_commit=0);

  設置流的auto_commit標誌。默認情況下,該標誌被置1,即當輸出緩衝區刷新時,當前的事務被自動提交。

  注意流的auto_commit標誌和數據庫的自動提交模型沒有任何關係。

(4)void set_flush(const bool auto_flush=true);

  設置auto_flush標誌。默認情況下auto_flush的值爲true, 即如果緩衝區出現髒數據則在流的析構函數中刷新緩衝區。如果自動刷新標誌被關閉,則需要使用close()方法或者flush()方法對流進行刷新。

  注意該函數僅僅能夠設置流的析構函數中是否自動刷新,並不是通常意義上的緩衝區刷新。

(5)voidflush(void);

  刷新流的輸出緩衝區。當輸出緩衝區被填滿時,緩衝區將被自動刷新。如果流的auto_commit標誌被置上,則在刷新完畢後當前事務被提交。

•otl_connect類

otl_connect類封裝了一系列有關數據庫連接的功能:建立連接、斷開連接、事務提交、事務回滾等等。換言之,otl_connect是在C++編程中創建和使用數據庫連接以及進行數據庫事務管理的類,主要方法有:

(1)static int otl_initialize(const int threaded_mode=0);

該靜態方法的主要功能是初始化OTL數據庫環境,程序中第一次建立與數據庫的連接之前,必須調用該方法一次,其後再建立與數據庫的連接,就不需要調用該方法了。如果程序是在多線程環境下訪問數據庫,參數threaded_mode需置爲1。另外在多線程環境下訪問數據庫,不要多個線程操作同一個otl_connect對象,除非該ot_connect對象有互斥鎖機制。

(2) otl_connect(const char* connect_str,const int auto_commit=0);

  連接數據庫。參數同rlogon(),見(3)rlogon()

(3) void rlogon(const char* connect_str,const int auto_commit=0);

     該方法的主要功能是建立與數據庫的連接。

     參數connect_str是數據庫連接配置字符串,有兩種表達形式

     o OTL4.0/OCIx

       ■”USER/PASSWORD”(本地數據庫)

       ■”USER/PASSWORD@TNS_ALIAS”(遠程數據庫)

     o OTL4.0/ODBC和OTL4.0/DB2_CLI

       ■”USER/PASSWORD@DSN”

       ■”DSN=value;UID=value;PWD=value”

     參數auto_commit設置數據庫事務的提交模式,auto_commit設置爲1,表示數

據庫事務自動提交;auto_commit設置爲0,表示數據庫事務非自動提交,auto_commit

缺省爲0。

(4) void logoff(void);

  該方法的主要功能是斷開與數據庫的連接。

(5) void commit(void);

  該方法的主要功能是提交數據庫事務。

(6) void rollback(void);

  該方法的主要功能是回滾數據庫事務。

(7) void auto_commit_off(void); void auto_commit_on(void);

  設置otl_connect對象的auto_commit標誌 

(8) long direct_exec(constchar *sqlstm,

  int ignore_error = otl_exception::enabled );

  直接執行靜態(無綁定變量)的SQL語句 ,該函數返回處理的行數。-1:處理異常;>=0:在執行INSERT、DELETE或UPDATE語句時,實際返回的是已處理行數

•otl_exception類

       otl_exception類用於描述OTL操作數據時拋出的異常,有3個主要的成員變量:

       (1)unsignedchar msg[1000];

       該成員變量用於保存存異常的具體錯誤信息。

       (2)char stm_text[2048];

       該成員變量用於保存導致發生異常錯誤的SQL語句。

       (3)char var_info[256];

       該成員變量用於保存導致發生異常錯誤的輸入/輸出變量。

OTL使用起來也很簡單,使用不同的數據庫連接,主要是根據需要在程

序開始的宏定義來指定的。OTL是首先根據這個宏定義來初始化數據庫

連接環境。OTL中用來區分連接方式的宏定義主要有下面這些:

OTL_ORA7,OTL_ORA8, OTL_ODBC, OTL_DB2_CLI, OTL_ODBC_MYSQL...

   不同的宏對應的數據庫API,具體說明如下:

宏定義名

說明

OTL_ORA7

for OCI7

OTL_ORA8

for OCI8

OTL_ORA8I

for OCI8i

OTL_ORA9I

for OCI9i. All code that compiles  and works under #define OTL_ORA7, OTL_ORA8, and OTL_ORA8I, should work when  OTL_ORA9I is used

OTL_ORA10G

for OCI10g. All code that compiles  and works  under #define OTL_ORA7,  OTL_ORA8, OTL_ORA8I, OTL_ORA9I, should work with OTL_ORA10G.

OTL_ORA10G_R2

for OCI10g, Release 2 (Oracle 10.2). All code that compiles and works under #define OTL_ORA7, OTL_ORA8, OTL_ORA8I, OTL_ORA9I, and OTL_ORA10G should work with OTL_ORA10G_R2

OTL_DB2_CLI

for DB2 Call Level Interface (CLI)

OTL_INFORMIX_CLI

for Informix Call Level Interface  for Unix (when  OTL_ODBC_UNIX is  enabled).

OTL_IODBC_BSD

for ODBC on BSD Unix, when iODBC  package is used

OTL_ODBC

for ODBC

OTL_ODBC_MYSQL

for MyODBC/MySQL. The difference  between OTL_ODBC_MYSQL and OTL_ODBC is that transactional ODBC function calls  are turned off for OTL_ODBC_MYSQL, since MySQL does not have transactions

OTL_ODBC_

POSTGRESQL

for the PostgreSQL ODBC driver 3.5  (and higher) that are connected to PostgerSQL 7.4 / 8.0  (and higher)  servers.

OTL_ODBC_UNIX

for ODBC bridges in Unix

OTL_ODBC_zOS

for ODBC on IBM zOS.

OTL_ODBC_XTG_IBASE6

for Interbase 6.x via XTG Systems'  ODBC driver. The reason for introducing  this #define is that the ODBC driver is the only Open Source ODBC driver for Interbase. Other drivers, like Easysoft's ODBC for Interbase, are commercial products, and it  beats the purpose of using Interbase, as an Open Source.database server.

綁定變量

•示例:

  INSERT INTO my_table (employee_id, supervisor_name)VALUES(

  :employee_id<int>,

  :supervisor_name<char[33]>)

•placeholder(比如employee_id)可以用沒有意義的f1代替,但是在一個SQL語句中不能使用相同名字的placeholder
•在執行INSERT語句的時候,如果數據庫中char字段的大小是n,則這個INSERT語句的綁定變量的大小要爲n+1;否則當邦定變量的大小爲n時,執行INSERT會出錯。
•對數據庫中定義的數字字段,可以根據字段的大小使用16位、32 位的整數和double類型;當然,如果對所有OCI的數字字段使用double,也不會出錯。
•OTL的一般使用步驟包括:

(1)  使用宏指明底層數據庫API類型和控制編譯器對OTL的編譯。例如:#define OTL_ORA9I      // Compile OTL 4.0/OCI9i

(2)  創建otl_connect對象,該對象一般爲全局共享的。

(3)  調用otl_connect的靜態方法otl_initialize()初始化OTL環境。

(4)  調用otl_connect的rlogon()方法連接數據庫。

(5)  創建otl_stream()對象,該對象一般爲局部的。

(6)  使用otl_stream的<<操作符綁定SQL中的變量。

(7)  使用otl_stream的>>操作符讀取返回結果。

(8)  調用otl_connect的logoff()方法從數據庫斷開。

 

代碼

#include <iostream>
  using namespace std;
  #include <stdio.h>

  #define OTL_ORA9I // Compile OTL 4.0/OCI9i,
  //#define OTL_UNICODE //Enable Unicode OTL for OCI9i
  #include <otlv4.h> // include the OTL 4.0 header file
  otl_connect db; // connect object

  void insert();void insertConstant();void insertBatch(); 
  void insertNoAutoCommit();
  void select();
  void update();void updateNoAutoCommit();void del();
  
  int main()
  {
     otl_connect::otl_initialize(); // initialize OCI environment
     try{
          db.rlogon("dbuser/dbpwd"); // connect to Oracle
otl_cursor::direct_exec
           ( 
            db, 
            "drop table person_tab",
            otl_exception::disabled // disable OTL exceptions
            ); // drop table

           otl_cursor::direct_exec
           (
            db,
            "create table person_tab(age number, name varchar2(30))"
            );  // create table

           insert(); // insert one records into table
           insertConstant();//constand insert sql
           insertBatch(); // insert batch records into table
           insertNoAutoCommit();//insert no  auto commit;
           select(); // select records from table
           update(); // update records in   table
           updateNoAutoCommit(); // update no auto commit
           del(); // delete records from table 
         }

catch(otl_exception& p){ // intercept OTL exceptions
        cerr<<p.msg<<endl; // print out error message
        cerr<<p.stm_text<<endl; // print out SQL that caused the error
        cerr<<p.var_info<<endl; // print out the variable that caused      
                                // the error
    }
 db.logoff(); // disconnect from Oracle
 return 0;
}
void insert()//插入單條數據數據
{ // create insert stream
  otl_stream o(1, // buffer size
            "insert into person_tab values(:v_age<int>,:v_name<char[31]>)", 
               // INSERT statement
               db // connect object
               );
   o<<30;//assigning :v_age=30
   o<<“dengkf”;//assigning :v_name=“dengkf”
   //char tmp[32];sprintf(tmp,”鄧科峯”);
   //o<<(unsigned char*)tmp;
   //INSERT automatically executes when all input variables are assigned. 
}

void insertBatch()//批量插入數據
{ 
  // create insert stream
  otl_stream o(10000, // buffer size
            "insert into person_tab values(:v_age<int>,:v_name<char[31]>)", 
               db // connect object
               );
   char tmp[32];
   
   for(int i=1;i<=10000;i++){
     sprintf(tmp,“NAME%d”,i);
     o<<i;
     o<<tmp;
   }
  //INSERT automatically executes when all input variables are assigned.
}         void insertNoAutoCommit()//插入數據(事務手動提交)
{ 
  // create insert stream
  otl_stream o(10001, // buffer size
            "insert into person_tab values(:v_age<int>,:v_name<char[31]>)", 
               db // connect object
               );
   o.set_flush(false);//turning off the stream’s autoflush flag
   o.set_commit(0);//turning off the stream's autocommit flag
   char tmp[32];
   
   for(int i=1;i<=10000;i++){
     sprintf(tmp,“NAME%d”,i);
     o<<i;
     o<<tmp;
   }
   o.flush();//flushing the stream's buffer
   db.commit();//committing the changes to the database 
}
    void select()//檢索數據
{  
  // create select stream
  otl_stream i(50, // buffer size
               "select * from person_tab where name=:v_name<char[31]>",
               // SELECT statement
               db // connect object
               );  
  i<<"dengkf"; // assigning :v_name = 8
  // SELECT automatically executes when all input variables are
  // assigned. First portion of output rows is fetched to the buffer

  int  r_age;
  char r_name[31];  

  while(!i.eof()){ // while not end-of-data
    i>>r_age;
    i>>r_name;
    cout<<"age="<<r_age<<endl;
    cout<<"name="<<r_name<<endl;
  }
}
//修改數據(事務自動提交)
void update()
{  
  // create update stream
  otl_stream s(1, // buffer size
               "update person_tab set age=:v_age<int> where 
                name=:v_name<char[31]>",
               // UPDATE statement
               db // connect object
               );  
  s<<31;//assgining :v_age =31
  s<<"dengkf"; //assigning :v_name = 8
  //UPDATE automatically executes when all input variables are assigned.
}
//修改數據(事務手動提交)
void updateNoAutoCommit()
{  
  // create update stream
  otl_stream s(2, // buffer size
               "update person_tab set age=:v_age<int> where age<:v_age2<int>",// UPDATE statement
               db // connect object
               );  
   s.set_flush(false);            
   s.set_commit(0);             
               
  s<<31;//assgining :v_age =31
  s<<2000; //assigning :v_age2 = 2000
  
  s.flush();
  db.commit();
  
}
//刪除數據
void del()
{  
  // create delete stream
  otl_stream l(1, // buffer size
               “delete from person_tab where name=:v_name<char[31]>",
               // DELETE statement
               db // connect object
               );  
  l<<"dengkf"; //assigning :v_name = 8
  //DELETE automatically executes when all input variables are assigned.
}


 

SQL常用舉例(常量SQL使用):

常量SQL就是不帶任何綁定變量的SQL,OTL通過一個靜態方法來操作:

long otl_cursor::direct_exec(otl_connect&db,//OTL數據庫對象

const char* sqltm,//SQL語句

otl_exception_disable=0,//OTL異常忽略標誌

);

返回值:

●-1,如果otl_exception_disable被設置成1,並且OTL的底層API發生錯誤

●>=0,SQL執行成功,返回實際處理成功的記錄數.

o Examples(Oracle)

代碼

   otl_cursor::direct_exec
    (db, // connect object
     "create table person_tab(age number, name varchar2(30))"
     );  // create table

   otl_cursor::direct_exec
    (db, // connect object
     "drop table persion_tab", // SQL statement
     otl_exception::disabled // disable OTL exceptions,
                            // in other words, ignore any
                            // database error
     ); // drop table

long rpc=otl_cursor::direct_exec
            (db,//connect object
            “delete from persion_tab”);

   o Examples(ODBC,DB2-CLI) 
   otl_cursor::direct_exec 
    (db, // connect object
     "create table person_tab(age numeric, name varchar(30))"
     );  // create table

   otl_cursor::direct_exec
    (db, // connect object 
     "drop table persion_tab", // SQL statement
     otl_exception::disabled // disable OTL exceptions,
                            // in other words, ignore any
                            //  database error
     ); // drop table 
    
   long rpc=otl_cursor::direct_exec
            (db,//connect object
            “delete from persion_tab”);

//“OtlPlsqlExample.cpp”
#include <iostream>
using namespace std;

#include <stdio.h>
#define OTL_ORA9I // Compile OTL 4.0/OCI9i
#include <otlv4.h> // include the OTL 4.0 header file

otl_connect db; // connect object

void plsql(void)
// invoking PL/SQL block
{ 
 otl_stream o(50, // buffer size
              "begin "
              " :A<int,inout> := :A+1; "
              " :B<char[31],out> := :C<char[31],in>; "
              "end;",
                 // PL/SQL block
              db // connect object
             );
o.set_commit(0); // set stream auto-commit off since 
                  // the block does not have any transactions 
                  // to commit
 o<<1<<"Test String1"; // assigning :A = 1, :C = "Test String1"
 o<<2<<"Test String2"; // assigning :A = 2, :C = "Test String2"
 o<<3<<"Test String3"; // assigning :A = 3, :C = "Test String3"

 o.flush(); // executing PL/SQL block 3 times

 int a;
 char b[32];

 while(!o.eof()){ // not end-of-data
  o>>a>>b;
  cout<<"A="<<a<<", B="<<b<<endl;
 }

}


int main()
{
 otl_connect::otl_initialize(); // initialize OCI environment
 try{

  db.rlogon(“dbuser/dbpwd"); // connect to Oracle

  plsql();//invoking PL/SQL block

 }

 catch(otl_exception& p){ // intercept OTL exceptions
  cerr<<p.msg<<endl; // print out error message
  cerr<<p.stm_text<<endl; // print out SQL that caused the error
  cerr<<p.var_info<<endl; // print out the variable that caused the  
                          // error
 }

 db.logoff(); // disconnect from Oracle

 return 0;
}


 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章