Linux 下進行 OCCI ( Oracle C++ Call Interface ) 開發
Linux 下進行 OCCI ( Oracle C++ Call Interface ) 開發
Oracle 呼叫介面 (Orale Call Interface,OCI) 是最全面、效能最高、基於原生“C”語言的 Oracle 資料庫介面,它可以提供 Oracle 資料庫的全部功能。
OCI 為構建各種語言專用介面(如 Oracle JDBC-OCI、ODP.Net、Oracle 預編譯器、Oracle ODBC 和 Oracle C++ Call Interface (OCCI)驅動程式)提供了基礎。
使用C/C++操作Oracle資料庫,我們經常採用 Oracle C++ Call Interface (OCCI) 來進行程式設計,下面介紹 Linux 下如何做 OCCI 開發.
要在Linux 下做 OCCI 開發,首先必須在開發機器上安裝有 OCCI 相關庫(包含開發所需的庫和執行所需的庫)和標頭檔案,OCCI 庫和標頭檔案可以通過以下三種途徑得到:
(1) 安裝 Oracle 資料庫引擎
(2) 安裝 Oracle Client
(3) 安裝 Oracle Instant Client.
其中,前兩種方式下,
庫所在位置一般是:$(ORACLE_HOME)/product/11.2.0.1.0/db_1/lib
標頭檔案所在位置一般是:$(ORACLE_HOME)/product/11.2.0.1.0/db_1/rdbms/public/
只要安裝了Oracle資料庫引擎或者客戶端,庫檔案和標頭檔案就能夠很方便的得到。然而,通常我們的開發都是安裝一臺資料庫伺服器,然後在客戶機器上做開發,所以安裝Oracle資料庫引擎不可取,鑑於安裝Oracle Client也相對比較繁瑣,我們採用第三種方式可以減少很多不必要的工作。儘管如此,我們還是有必要首先簡單介紹在前兩種方式下如何做OCCI開發。
(1) OCCI 開發方式一
** (i)編譯**
編寫好程式後,Makefile 定義相關變數,然後進行編譯,例如:
OCCI_HOME= /sdd1/oracle/11gR2_database_X64/product/11.2.0.1.0/db_1 OCCI_INCLUDE_DIR=$(OCCI_HOME)/rdbms/public/ OCCI_LIBRARY_PATH=$(OCCI_HOME)/lib default: g++ *.cpp -I$(OCCI_INCLUDE_DIR) -L$(OCCI_LIBRARY_PATH) -locci -lclntsh
** (ii)執行**
編譯完成後,執行程式,執行OCCI程式必須設定以下環節變數:
export ORACLE_BASE=/sdb1/oracle/11gR2_database_X64
export ORACLE_HOME=$ORACLE_BASE/product/11.2.0.1.0/db_1
export NLS_LANG='simplified chinese'_china.ZHS16GBK
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH
** (iii) 附加問題**
若想將OCCI標頭檔案和庫檔案拷貝到其它機器進行OCCI開發,則按如下步驟做,參照http://blog.csdn.net/zklth/article/details/7184032 :
(1) 方法一:使用 Oracle 11.2.0.1 資料庫軟體中自帶的 OCCI 相關庫和標頭檔案.
在一個安裝好Oracle 11.2.0.1 R2 資料庫的機器上拷貝occi相關標頭檔案和庫檔案到目錄 /opt/OCCI_11g_R2/include 和 /opt/OCCI_11g_R2/lib 下,
標頭檔案:
mkdir /opt/OCCI_11g_R2/include
cp -r /sdd1/oracle/11gR2_database_X64/product/11.2.0.1.0/db_1/rdbms/public/* /opt/OCCI_11g_R2/include/
庫檔案:
mkdir /opt/OCCI_11g_R2/lib
cp /sdd1/oracle/11gR2_database_X64/product/11.2.0.1.0/db_1/lib/libclntsh.so.11.1 /opt/OCCI_11g_R2/lib/
cp /sdd1/oracle/11gR2_database_X64/product/11.2.0.1.0/db_1/lib/libocci.so.11.1 /opt/OCCI_11g_R2/lib/
cp /sdd1/oracle/11gR2_database_X64/product/11.2.0.1.0/db_1/libocci11.a /opt/OCCI_11g_R2/lib/
cp /sdd1/oracle/11gR2_database_X64/product/11.2.0.1.0/db_1/libnnz11.so /opt/OCCI_11g_R2/lib/
cp /sdd1/oracle/11gR2_database_X64/product/11.2.0.1.0/db_1/libnnz11.a /opt/OCCI_11g_R2/lib/
cd /opt/OCCI_11g_R2/lib
建立3個軟連結
ln -s libocci.so.11.1 libocci.so
ln -s libclntsh.so.11.1 libclntsh.so
ln -s libclntsh.so libclntsh.so.10.1
[root@localhost lib]# ll
總計 69764
lrwxrwxrwx 1 root root 17 01-07 13:33 libclntsh.so -> libclntsh.so.11.1
lrwxrwxrwx 1 root root 12 01-07 13:33 libclntsh.so.10.1 -> libclntsh.so
-rwxr-xr-x 1 root root 48724689 01-07 12:58 libclntsh.so.11.1
-rw-r--r-- 1 root root 11595642 2012-01-07 libnnz11.a
-rw-r--r-- 1 root root 7899997 2012-01-07 libnnz11.so
-rw-r--r-- 1 root root 1863334 01-07 12:50 libocci11.a
lrwxrwxrwx 1 root root 15 01-07 13:33 libocci.so -> libocci.so.11.1
-rwxr-xr-x 1 root root 1260923 01-07 12:50 libocci.so.11.1
編譯OCCI程式時使用如下選項:
OCCI_HOME=/opt/OCCI_11g_R2
OCCI_INCLUDE_DIR=$(OCCI_HOME)/include
OCCI_LIBRARY_PATH=$(OCCI_HOME)/lib
g++ *.cpp -I$(OCCI_INCLUDE_DIR) -L$(OCCI_LIBRARY_PATH) -locci -lclntsh -lnnz11 # 注意要加上 lnnz11,libclntsh.so 中使用到了 libnnz11.so 中的函式.
編譯成功!
(2) 安裝 ORACLE Instant Client 做 OCCI 開發
(i) 安裝ORACLE Instant Client
安裝請參見帖 http://blog.csdn.net/zklth/article/details/7190035 或者 http://blog.csdn.net/zklth/article/details/7184032
包含 zip 安裝 和 rpm 安裝. 注意,做開發必須安裝 basic、sdk 兩個包.
對於 zip 包.
開發相關的標頭檔案在:/root/linux-11.2.0.1.0-1.x86_64/instantclient_11_2/sdk/include
開發相關的庫檔案在:/root/linux-11.2.0.1.0-1.x86_64/instantclient_11_2.
對於rpm包
開發相關的標頭檔案在:/usr/include/oracle/11.2/client64
開發相關的庫檔案在:/usr/lib/oracle/11.2/client64/lib
安裝完畢,進入庫檔案所在目錄,建立如下2個軟連結:
ln -s libclntsh.so.11.1 libclntsh.so
ln -s libocci.so.11.1 libocci.so
** (ii) 編譯 OCCI 程式**
這裡以zip安裝為例, Oracle Instant Client 安裝路徑是:/root/linux-11.2.0.1.0-1.x86_64/instantclient_11_2.
Makefile 按如下方式書寫.
OCCI_INCLUDE_DIR=/root/linux-11.2.0.1.0-1.x86_64/instantclient_11_2/sdk/include
OCCI_LIBRARY_PATH=/root/linux-11.2.0.1.0-1.x86_64/instantclient_11_2
default:
g++ -o test test.cpp DBwrapper.cpp -I$(OCCI_INCLUDE_DIR) -L$(OCCI_LIBRARY_PATH) -locci -lclntsh
(iii)執行
編譯完成後,執行程式,執行OCCI程式必須設定以下環節變數:
export ORACLE_HOME=/root/linux-11.2.0.1.0-1.x86_64/instantclient_11_2
export NLS_LANG='simplified chinese'_china.ZHS16GBK
export LD_LIBRARY_PATH=$ORACLE_HOME:$LD_LIBRARY_PATH
建議寫一個指令碼執行程式,在指令碼中設定這些環境變數.
附: 示例程式碼
//
// File: DBwrapper.h
// Author: zhankunlin
// Date: 2011-12-6
// Desc: Operate database.
//
#ifndef DBOP_H
#define DBOP_H
#include<string>
#include<map>
#include<vector>
using std::string;
using std::map;
using std::vector;
#include "occi.h"
using oracle::occi::Environment;
using oracle::occi::Connection;
using oracle::occi::Statement;
using oracle::occi::ResultSet;
using oracle::occi::SQLException;
class DBwrapper
{
public:
DBwrapper();
DBwrapper(string confFilePath);
DBwrapper(string user,string pwd,string conStr);
~DBwrapper();
void readConfFile();
bool open();
bool close();
bool commit();
void setSQL(string oneSQL);
bool execSQL(string sqlStr,string op);
bool execQuerySQL();
Statement* getStatement();
ResultSet* getResultSet();
bool execUpdateSQL();
bool execBatchedUpdate();
void generateSQL(map<string,string> oneSQLKV); /* generate one SQL string */
// vector<string> generateSQL(vector<map<string,string>> multiSql); /* generate multiple SQL string */
map<string,string> execSQL(string strSQL); /* execute one SQL string */
// vector<map<string,string>> execSQL(vector<string> strSQLs); /* execute multiple SQL string */
private:
Environment *env; /* in $ORACLE_HOME/rdbms/public/occiControl.h */
Connection *conn;
Statement *stmt;
ResultSet *rs;
string strSQL;
string user;
string password;
string conStr;
string confFilePath;
};
#endif
//
// File: DBwrapper.cpp
// Author: zhankunlin
// Date: 2011-12-6
// Desc: Operate database.
//
#include "DBwrapper.h"
#include<iostream>
#include<string>
#include<map>
#include<vector>
using std::string;
using std::map;
using std::vector;
using std::cout;
using std::endl;
using std::ios;
#include <fstream>
using std::ifstream;
#include "occi.h"
using oracle::occi::Environment;
using oracle::occi::Connection;
using oracle::occi::Statement;
using oracle::occi::ResultSet;
using oracle::occi::SQLException;
DBwrapper::DBwrapper()
{
this->confFilePath = "conf//server.conf";
readConfFile();
}
DBwrapper::DBwrapper(string confFilePath)
{
this->confFilePath = confFilePath;
readConfFile();
}
DBwrapper::DBwrapper(string user,string conStr)
{
this->user = user;
this->password = pwd;
this->conStr = conStr;
}
void DBwrapper::readConfFile()
{
ifstream configFile(this->confFilePath.c_str(),ios::in);
if( !configFile.is_open() ) {
cout<< "Open file "<< this->confFilePath << " failed!" <<endl;
return;
}
string line,name,value;
int len=0,start=0;
while( configFile >> line )
{
if( line.find('#') != string::npos ) /* annotation */
continue;
if( line.find("=") == string::npos ) /* not found = */
continue;
len=line.length();
start=line.find("="); /* = 的下標 */
name=line.substr(0,start);
value=line.substr(start+1,len-(start+1));
if(name == "db_user") {
this->user = value;
}
if(name == "db_user_pwd") {
this->password = value;
}
if(name == "db_con_str") {
this->conStr = value;
}
}
cout<< "-------- Read configure file -------" <<endl;
cout<< "file: " << this->confFilePath <<endl;
cout<< "db_user: " << user <<endl;
cout<< "db_user_pwd: " << password <<endl;
cout<< "db_con_str: " << conStr <<endl;
cout<< "---------------------------------------" <<endl;
}
DBwrapper::~DBwrapper()
{
}
//
// Desc:
// Open connection to Oracle database.
// Return:
// true -- Successful.
// false -- Failed.
//
bool DBwrapper::open()
{
try {
env = Environment::createEnvironment(Environment::OBJECT);
conn = env->createConnection(user,password,conStr);
stmt = conn->createStatement();
} catch (SQLException ex) {
cout<<"Exception: Code - "<<ex.getErrorCode()<<",Message - "<<ex.getMessage();
return false;
}
return true;
}
//
// Desc:
// Close connection to Oracle database.
// Return:
// true -- Successful.
// false -- Failed.
//
bool DBwrapper::close()
{
try {
env->terminateConnection(conn);
Environment::terminateEnvironment(env);
} catch (SQLException ex) {
cout<<"Exception: Code - "<<ex.getErrorCode()<<",Message - "<<ex.getMessage();
return false;
}
return true;
}
//
// Desc:
// commit the operation.
// Return:
// true -- Successful.
// false -- Failed.
//
bool DBwrapper::commit()
{
try {
conn->commit();
} catch (SQLException ex) {
cout<<"Exception: Code - "<<ex.getErrorCode()<<",Message - "<<ex.getMessage();
return false;
}
return true;
}
void DBwrapper::setSQL(string oneSQL)
{
strSQL = oneSQL;
}
/* generate one SQL string */
void DBwrapper::generateSQL(map<string,string> oneSQLKV)
{
string oneSQL="";
strSQL = oneSQL;
}
bool DBwrapper::execBatchedUpdate()
{
try {
stmt->executeUpdate();
} catch (SQLException ex) {
cout<<"Exception: Code - "<<ex.getErrorCode()<<",Message - "<<ex.getMessage();
return false;
}
return true;
}
bool DBwrapper::execUpdateSQL()
{
try {
stmt->setSQL(strSQL);
stmt->executeUpdate();
} catch (SQLException ex) {
cout<<"Exception: Code - "<<ex.getErrorCode()<<",Message - "<<ex.getMessage();
return false;
}
return true;
}
bool DBwrapper::execQuerySQL()
{
try {
stmt->setSQL(strSQL);
rs = stmt->executeQuery();
} catch (SQLException ex) {
cout<<"Exception: Code - "<<ex.getErrorCode()<<",Message - "<<ex.getMessage();
return false;
}
return true;
}
ResultSet* DBwrapper::getResultSet()
{
return rs;
}
Statement* DBwrapper::getStatement()
{
return stmt;
}
//
// Desc:
// execute SQL string.
// Parameters:
// string sqlStr -- SQL string
// string op -- it has only four value.
// insert,update,delete,select
//
bool DBwrapper::execSQL(string sqlStr,string op)
{
if(!(op == "insert" || op == "update" ||
op == "delete" || op == "select")) {
cout<<"SQL operation must be in 'insert,select'!"<<endl;
return false;
}
strSQL = sqlStr;
if(op == "select")
return execQuerySQL();
else
return execUpdateSQL();
}