本篇文章来源于 Linux公社网站(www.linuxidc.com) 原文链接:http://www.linuxidc.com/Linux/2011-05/35930.htm
有点空,和新上手occi的筒子们一起总结下。这篇内容其实挺有用的,对于新人来说不管哪一方面都是一个难点,如oracle、unix、c++与occi、shell、makefile、随便挑出一个名词就能够让人学上一阵子了。这篇文章呢,咱就来个彻底的大剖析,目的是连通oracle并进行C++的应用编程,并在这个基础上,对我们以后每个名词点的深入学习,提供入门的作用。
首先说一下我的环境,(注:大家的工作环境千差万别,但万变不离其宗,今天着重讲这个宗,所以不必拘泥于环境如何,看了我的操作,希望能使你举一反三,各种环境都能应对自如。)由于公司结构不得不形成如下的工作环境:
本人主机:windows+secureCRT,所以我都是在使用远程
工作主机:unix+oracle(本人是oracle服务器端,其实客户端的问题不大后详细解释。)
数据库服务器:我只知道主机ip、数据库用户名及密码,其他都不知道。应该是大型主机。
这种环境貌似是三方,而实际工作是两方,因为我是用windows+secureCRT远程连接到unix工作机上,在unix上编写c++程序调用occi连接远程数据库服务器。所以描述重心是后两者的工作。至于secureCRT(可以是其他ssh工具)连接到unix则需要unix主机的ip地址、用户名及密码即可。
好了,下面的所有工作都是从登陆unix工作机这一刻开始,目标是在unix上编写一段连接远程oracle数据库的c++代码编译、连接、运行成功。各个击破吧!
第一步:编译、连接、运行C++程序,保证C++环境正确。
判断C++环境正确很简单,写个helloworld.cpp程序。代码如:
#include <iostream>
using namespace std;
main()
{
cout<<"hello world!"<<endl;
}
这段代码要包含区别于c的元素,如using语句、cout等;在shell里(sh、bash均可,个人更喜欢bash。)运行编译命令:
CC -c helloworld.cpp
(
注意此处为大写的CC,小写的cc是编译c语言的)。结果会生成helloworld.o文件,继续运行连接命令:
CC -o helloworld.o
结果会默认生成a.out文件,此时当前目录下执行 ./a.out 出现打印的hello world!则为成功了(不要漏掉点和斜杠./),C++的编译环境就这样完成了。
unix默认都会支持CC的,至于gcc那是linux上的gnu项目开发的unix不一定支持。
第二步:环境变量配置及撰写Makefile文件
1、Unix环境变量的配置这里所说的环境变量是指oracle安装的dll等资源路径。因为若cpp文件经过编译链接,执行的时候需要occi资源的支持的,没有支持就会报错说.dll文件找不到之类。所以在makefile之前可以先把环境变量搞定了,内容很简单,看setenv.sh脚本代码:
ORACLE_HOME = /opt/app/ora10g/product/10.2.0; export ORACLE_HOME
PATH = /usr/ccs/bin:$ORACLE_HOME/bin:$PATH; export PATH
LD_LIBRARY_PATH = $ORACLE_HOME/lib32:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH
注释:
ORACLE_HOME变量是产品根目录,就是有很多文件的上一级;
PATH中第一个/usr/ccs/bin是我用的make路径,这样每次就不用绝对地址了,直接make就行了。
$ORACLE_HOME/bin:$PATH路径下包含oracle提供的可执行文件。
LD_LIBRARY_PATH=$ORACLE_HOME/lib32为后面的cpp对应执行文件提供dll。
这里多提一下lib和lib32的区别吧,在oracle9i还是10g或更新的oracle,lib32表示的是32位的环境,而lib表示的是64位的环境。所以根据个人情况改写吧,对于makefile也是这样的。
setenv.sh的使用:
setenv.sh是一个shell脚本,可以手动执行./setenv.sh,这样你就能享受这些环境变量了,也可以自动执行,关于怎样自动执行建议看看.profile等文件相关内容,(本人喜欢bash环境,每次运行bash时会自动依次执行.bash_profile、.bashrc,所以在.bashrc中加入/setenv.sh即可。
bashrc内容是:
注意看最后一行指明了要运行setenv.sh,这样就不用手动执行了
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
#open core file
ulimit -S -c unlimited > /dev/null 2>&1
#time zone
# User specific aliases and functions
. ./zxliu/setenv.sh
2、Makefile的编写
在开始调用occi之前,首先需要在helloworld工作目录写一份Makefile文件,起名为makefile均可,make命令首先寻找Makefile,若不存在则会寻找makefile。
这时也要确认能否执行make命令,如果显示找不到,需要使用绝对地址执行make,如/usr/ccs/bin/make,默认unix均有make执行文件。
该Makefile内容如下:
###########################################
#Makefile for the OCCI demo programs
###########################################
#ORACLE_HOME变量指明unix上的oracle产品路径
ORACLE_HOME=/opt/app/ora10g/product/10.2.0
#ORACLE_INCLUDES变量指明产品路径下的各种include文件$()表示取值,注明这些文件对于后面cpp编译中include occi头文件很重要
ORACLE_INCLUDES=-I$(ORACLE_HOME)/rdbms/demo \
-I$(ORACLE_HOME)/rdbms/public \
-I$(ORACLE_HOME)/plsql/public \
-I$(ORACLE_HOME)/network/public \
-I$(ORACLE_HOME)/precomp/public
#ORACLE_LIBS变量指明,链接库,编译程序的时候很重要,而INC和LIB是连接程序时候需要的。-I表示引入的是头文件,-L表示引入的是动态链接库,-l表示在-L中连接的文件如clntsh.dll文件和occi.dll文件。所以-l必须和-L配合使用。
ORACLE_LIBS=-L$(ORACLE_HOME)/lib32 -L$(ORACLE_HOME)/rdbms/lib32
INC=$(ORACLE_INCLUDES)
LIB=$(ORACLE_LIBS) -lclntsh -locci
#为方便取下面三个变量,目标为helloworld,源文件是helloworld.cpp,编译后文件helloworld.o
PRG=helloworld
SRC=../../helloworld.cpp
OBJ=helloworld.o
#下面是常规的makefile内容,$@表示依次取目标执行,这里只有helloworld一个目标。实际等价于
#CC -o helloworld helloworld.o 不过加入了include和lib文件。而helloworld.o需要后续完成
$(PRG):$(OBJ)
@echo "begin link......"
CC $(INC) $(LIB) -o $@ $(OBJ)
#helloworld目标依赖helloworld.o生成,所以该句就是编译.c生成.o文件。只不过加入了include和lib文件
$(OBJ):$(SRC)
@echo "begin compile......"
CC $(INC) $(ORACLE_LIBS) -c $(SRC)
#后面的内容不是make的内容了,而是make clean内容。比如想重新make之前,清除.o等文件,执行make clean语句
#.PRNOY语句表明 clean关键词是个伪目标。make不自动执行。
.PRONY:clean
clean:
@echo "Removing linked and compiled files......"
rm -f $(OBJ) $(PRG)
写到这里,Makefile写完了,至于是否正确需要实际验证,因为每个人的oracle安装的不一样,所以里面的变量内容需要酌情更改,按照我说的更改即可。
验证方法很简单,执行make命令(或绝对路径用make),看是否能够编译.cpp并生成.o及最后的目标文件。一步一步检查看哪里存在问题。问题常常是oracle路径的问题要设置好。其实路径无非是编译需要的和链接需要的include及dll文件而已。所以根据这个思想去你的oracle目录下去找他们吧。 Makefile很关键,没写好的留言讨论。
验证代码如下://代码的目的就是验证makefile中oracle的头文件和lib文件路径是否正确了
#include <iostream>
#include <occi.h>
using namespace std;
using namespace oracle::occi;
main()
{
Environment *env=Environment::createEnvironment();
cout<<"success"<<endl;
}
注:编译好了,执行一下看是否输出success第三步另起一篇,第三篇是在c++及makefile环境没问题的情况下如何访问远程oracle数据库了。
哈哈,说是交互编程,只负责登陆成功而已。
第三步,程序中登陆远程数据库。
1、验证unix有无配置远程数据库的信息(unix本地服务名设置)unix cd到oracle的目录去,找/opt/app/ora10g/product/10.2.0/network/admin/tnsnames.ora文件。嗯是的,就是这个文件,tns名称服务文件,这个文件里指明了远程服务器的ip等信息。www.linuxidc.com无论装的是oracle服务端还是客户端还是instant client都必须找到这个文件,哪怕自己建(instant client可能要自己建)。vi tnsnames.ora 看是否有如下信息段:
DBDEMO =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 10.6.6.15)(PORT = 1521))
(LOAD_BALANCE = no)
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = testDB)
(FAILOVER_MODE =
(TYPE = SELECT)
(METHOD = BASIC)
(RETRIES = 180)
(DELAY = 5)
)
)
)
这个信息段可以自定义多种信息,可以搜索看看,但核心是指明DBDEMO是unix端起得服务名,可以任意起名但cpp文件里要用到的,而HOST = 10.6.6.15是远程数据库所在地址。SERVICE_NAME = testDB看是远程数据库的名(全局数据库名,顺便提一下远程数据库要设置监听程序,你懂的,我有篇文章介绍了客户端和服务端的链接原理),这个名字必须要正确。保证这几个要点可以看2.
2、cpp文件的编写。
先看代码吧
#include <iostream>
#include <occi.h>
using namespace std;
using namespace oracle::occi;
main()
{
Environment *env=Environment::createEnvironment();//create succ
string name = "name";
string pwd = "pwd";
string dbname = "DBDEMO";
try
{
Connection *conn=env->createConnection(name,pwd,dbname);
cout<<"conn succ!"<<endl;
env->terminateConnection(conn);
}
catch(SQLException e)
{
cout<<e.what()<<endl;
}
Environment::terminateEnvironment(env);
cout<<"end!"<<endl;
}
语句都能理解吧,就是建立链接,值得注意的是用户名和密码,以及DBDEMO名字,是unix配置的服务名,而不是远程oracle服务器的全局数据库名。本cpp是通过unix的network文件夹连接远程数据库服务器的。修改数据库内容就自己去学吧。还很多路要走。
ok,make、./helloworld 看看结果吧。