- 什么是OTL:OTL 是 Oracle, Odbc and DB2-CLI TemplateLibrary 的縮寫,是一個操控關系數據庫的C++模板庫,它目前幾乎支持所有的當前各種主流數據庫,如下表所示:
數據庫 |
訪問接口 |
支持版本 |
Oracle |
OCI |
OCI7、OCI8、OCI8i、OCI9i、OCI10g |
DB2 |
CLI |
DB2 CLI |
MS SQL Server 、Sybase、Informix 、MySQL、 Interbase/Firebird、PostgreSQL、SQLite、SAP/DB、TimesTen、MS ACCESS |
ODBC |
ODBC2.5、ODBC3.x |
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“流”的概念的具體表現形式,任何通過輸入/輸出參數使用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是在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操作數據時拋出的異常,有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]>)
(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; } 輸出: A=2,B=Test Stri ng1 A=3,B=Test String2 A=4,B=Test String3 常量PL/SQL塊的使用與常量SQL的使用類似,在此不再贅述。
下一篇:OTL使用指南