OCCI简介 Oracle® C++ Call Interface (OCCI) 是一套应用程序编程接口,它允许C++程序与一个或者多个Oracle数据库进行交互.OCCI给予你强大的数据库操作能力,比如说执行SQL,处理存储过程等. OCCI主要是提供给有以下需求的用户:
- 希望借助系统内存和网络连接的合理使用,开发高性能的应用程序.
- 开发可伸缩的应用程序,以满足数据库用户和请求的不断增长.
- 支持访问数据库对象.
- 简化用户认证和密码管理.
- 支持多层认证模式
- 两层C/S环境或者多层环境下,动态连接管理和事务管理的一致性接口.
注: OCCI不支持Non-Blocking(非阻塞)模式. 由于OCCI是以动态库方式导出的类库,因此对平台和编译器的依赖性比较强,所以需要根据不同平台,不同编译器取得对应的OCCI接口,并且在自己的程序中链接OCCI的库:
安装OCCI 一般情况下OCCI会随着oracle数据安装,附带安装到某个目录下,不过对于仅仅需要做相关开发的人员来说,这个动作”太大了”,选择安装即时客户端是一个不错的选择,小巧,便于配置,功能完善(对于应用程序开发来说). 我们需要到oracle的网站上下载以下几个东西:
- instantclient-basic (一些基础组件)
- instantclient-sdk (开发包,即相关的头文件和库文件)
- occi (能正确匹配你的开发环境的OCCI库)
虽然instantclient-sdk里已经有了lib和头文件,但occi仍然需要单独下载,因为 instantclient-sdk 只有发行版本的lib和动态库,对于开发和调试来说是不够的. instantclient-sdk 中的动态库不能直观的判断其CRT库的依赖版本 有一个地方还需要注意,OCCI版本并不是很全,因为它有太多的东西需要对号入座,如开发者的编译器类型,编译器版本,操作系统(x86,x64),Oracle客户端(包含即使客户端)版本.所以尽管OCCI有不少的发行版本,但轮到你具体选择的时候就不多了,比如说你想找支持VC2008的OCCI,你就只能选Oracle11的客户端了,因为Oracle只发行了这样一个版本同支持VC2008. 回到安装的话题上,假设你用windows +VC2008,你需要下载 instantclient-basic-win32-11.1.0.6.0.zip,instantclient-sdk-win32-11.1.0.6.0.zip,occivc9win32_111060.zip.为什么要选11.0.6这个版本?因为我们的开发环境决定了只能找到11.1.6.0这个版本的OCCI库.
- 先将下载到的instantclient-basic 解压到C:\ora_env.那么它下面应该有sdk;vc8;vc8;vc71这4个文件夹.
- 将instantclient-sdk-win32-11.1.0.6.0.zip中的sdk目录放在C:\ora_env下.
- 在C:\ora_env下新建文件夹vc9,将occivc9win32_111060.zip中的4个文件(oraocci11.dll,oraocci11d.dll,oraocci11.dll.manifest,oraocci11d.dll.manifest)放在里面.
- 在C:\ora_env\sdk\lib\msvc下新建目录vc9,将occivc9win32_111060.zip中的 oraocci11.lib,oraocci11d.lib放在这个目录里.
- 将C:\ora_env\vc9;C:\ora_env;加入PATH环境变量(最好放在前面).
- 新建一个环境变量TNS_AMDIN,值为C:\ora_env\;tnsnames.ora文件应该放在这个目录下.
- 新建一个环境变量NLS_LANG,值为SIMPLIFIED CHINESE_CHINA.ZHS16GBK(这个值根据自己的情况定).
- 删除C:\ora_env下的oraocci11.dll和oraocci11.sym,这个库文件不是链接到VC2008的CRT,C:\ora_env\vc9才是正确的DLL,同时也能更明确表达我们的是使用VC2008开发环境的这样一个情况.
- C:\ora_env\sdk\lib\msvc下的oraocci11.lib 也应该删除,原理同上.
- 将C:\ora_env\sdk\lib\msvc\vc9加入VC2008库文件搜索路径.
- 将C:\ora_env\sdk\include加入VC2008头文件搜索路径.
linux下的配置过程基本一样,但动态库文件(.so)的路径(对应于windows环境下的C:\ora_env\vc9)应该加入到LD_LIBRARY_PATH环境变量中.
开始编码 配置工作做完后,可以写一点代码,测试一下
View Code
1 /* 2 * A simple OCCI test application 3 * This file contains the Employees class declaration 4 */ 5 6 #include <occi.h> 7 #include <iostream> 8 #include <iomanip> 9 10 using namespace oracle::occi; 11 using namespace std; 12 13 class Employees { 14 public: 15 Employees(); 16 virtual ~Employees(); 17 18 void List(); 19 20 private: 21 Environment *env; 22 Connection *con; 23 24 string user; 25 string passwd; 26 string db; 27 }; 28 29 In Solution Explorer, right-click Source Files, select Add, select New Item… 30 31 In Add New Item, select C++ File (.cpp), enter Employees.cpp (or any name you prefer) in Name, and click Add. 32 33 Here's the content of the file on my system: 34 35 /* 36 * A simple OCCI test application 37 * This file contains the Employees class implementation 38 */ 39 40 #include "Employees.h" 41 42 using namespace std; 43 using namespace oracle::occi; 44 45 int main (void) 46 { 47 /* 48 * create an instance of the Employees class, 49 * invoke the List member, delete the instance, 50 * and prompt to continue... 51 */ 52 53 Employees *pEmployees = new Employees(); 54 55 pEmployees->List(); 56 57 delete pEmployees; 58 59 cout << "ENTER to continue..."; 60 61 cin.get(); 62 63 return 0; 64 } 65 66 Employees::Employees() 67 { 68 /* 69 * connect to the test database as the HR 70 * sample user and use the EZCONNECT method 71 * of specifying the connect string. Be sure 72 * to adjust for your environment! The format 73 * of the string is host:port/service_name 74 */ 75 76 user = "hr"; 77 passwd = "hr"; 78 db = "oel01:1521/OEL11GR1.SAND"; 79 80 env = Environment::createEnvironment(Environment::DEFAULT); 81 82 try 83 { 84 con = env->createConnection(user, passwd, db); 85 } 86 catch (SQLException& ex) 87 { 88 cout << ex.getMessage(); 89 90 exit(EXIT_FAILURE); 91 } 92 } 93 94 Employees::~Employees() 95 { 96 env->terminateConnection (con); 97 98 Environment::terminateEnvironment (env); 99 } 100 101 void Employees::List() 102 { 103 /* 104 * simple test method to select data from 105 * the employees table and display the results 106 */ 107 108 Statement *stmt = NULL; 109 ResultSet *rs = NULL; 110 string sql = "select employee_id, first_name, last_name " \ 111 "from employees order by last_name, first_name"; 112 113 try 114 { 115 stmt = con->createStatement(sql); 116 } 117 catch (SQLException& ex) 118 { 119 cout << ex.getMessage(); 120 } 121 122 if (stmt) 123 { 124 try 125 { 126 stmt->setPrefetchRowCount(32); 127 128 rs = stmt->executeQuery(); 129 } 130 catch (SQLException& ex) 131 { 132 cout << ex.getMessage(); 133 } 134 135 if (rs) 136 { 137 cout << endl << setw(8) << left << "ID" 138 << setw(22) << left << "FIRST NAME" 139 << setw(27) << left << "LAST NAME" 140 << endl; 141 cout << setw(8) << left << "======" 142 << setw(22) << left << "====================" 143 << setw(27) << left << "=========================" 144 << endl; 145 146 while (rs->next()) { 147 cout << setw(8) << left << rs->getString(1) 148 << setw(22) << left << (rs->isNull(2) ? "n/a" : rs->getString(2)) 149 << setw(27) << left << rs->getString(3) 150 << endl; 151 } 152 153 cout << endl; 154 155 stmt->closeResultSet(rs); 156 } 157 158 con->terminateStatement(stmt); 159 } 160 }
代码中的数据库连接字符串跟一般我们常用的有点不同,连接字符串可以有下面两种写法:
- host:[port][/service name]
- (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp) (HOST=127.0.0.1) (PORT=5521))
(CONNECT_DATA=http://www.cnblogs.com/cheen/archive/2012/01/09/(SERVICE_NAME=SRV_NAME))) 第二种就是跟tnsnames.ora中的内容一样的了.
常见错误处理 分享一些在开发和测试的过程中,经常会遇见一些常见的问题(win + VC). 编译代码时,发现大量错误,都是说某些CRT函数名称重复. 原因中多半是同一个项目静态链接了两个不同版本的CRT库.比如VC2005的程序A依赖VC2008的程序B(B使用OCCI),B的代码生成方式为/MT或者/MTd. 将上面的场景中,程序B的代码生成方式改成/MD或者/MDd后,编译通过,但是程序运行发生崩溃. 很可能是代码中的某个对象产生和释放分别调用了不同的CRT(一个是VC2005的,一个是VC2008的).解决办法:没有什么好的解决办法,最好还是统一开发环境吧,C++导出的类不适合跨环境. 出现ORA-24960错误 你的项目是debug版本,但链接了release版本的occi库. 出现R6034错误 OCCI库跟你的VC版本不一致. 调试时,发现堆栈被莫名其妙的破坏 同上,或者OCCI的debug与release版本跟当前项目的设置不匹配. 找不到MSVCR90.DLL 记得让你的客户安装VC9的redist. 找不到MSVCR90D.DLL 你发布的程序是调试版本的,虽然你的用户安装了VC9的redist,那也是没用的,因为redist只会安装release版本的运行时库. |