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 库和头文件可以通过以下三种途径得到:
(i) 安装 Oracle 数据库引擎 (2) 安装 Oracle Client (3) 安装 Oracle Instant Client.
其中,前两种方式下,
库所在位置一般是: /sdd1/oracle/11gR2_database_X64/product/11.2.0.1.0/db_1/lib
头文件所在位置一般是: /sdd1/oracle/11gR2_database_X64/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.youkuaiyun.com/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.youkuaiyun.com/zklth/article/details/7190035 或者 http://blog.youkuaiyun.com/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
建议写一个脚本运行程序,在脚本中设置这些环境变量.
附: 示例代码
- <span style="font-size:13px;">//
- // 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
- </span>
- //
- // 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 pwd, 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, update, delete, select'!"<<endl;
- return false;
- }
- strSQL = sqlStr;
- if(op == "select")
- return execQuerySQL();
- else
- return execUpdateSQL();
- }