天天看點

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/[email protected]_ALIAS”(遠端資料庫)

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

           ■”USER/[email protected]”

           ■”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;
    }