Tuxedo 与数据库互联
2.2.1 概述
在两层的 C/S结构中,客户端直接访问数据库,当采用TUXEDO中间件后,形成三层结构。这时,客户端
不直接访问数据库,而是改为调用中间件TUXEDO服务端上的服务,由TUXEDO服务端访问数据库,并把结果返回
给客户端。TUXEDO服务端可以和ORACLE在同一台服务器上,也可以在不同的机器上。如果在不同的机器上,在
TUXEDO的服务端所在的机器上要安装一个ORACLE的客户端。
TUXEDO服务端与ORACLE数据库连接有两种方式:1. 不通过 XA 接口直接互连。适用于整个系统只有一个数据库的情况。2. 通过 XA 接口互连,对整个系统有一个或多个数据库都适用,建议采用。
2.2.1 系统说明操作系统:WINDOW XP + SP2TUXEDO 版本:9.0 安装目录 c:\bea\tuxedo9.0ORACLE 版本:10g 安装目录 c:\oracle开发工具:VS 2005, VC 6.0
所有配置文件、源代码文件和执行程序所在目录:d:\zwtest
我根据自己的测试设置的环境变量,仅供在编译程序和启动tuxedo服务出错时比较1.用户环境变量
APPDIR,值为 :d:\zwtest
TUXCONFIG,值为:d:\zwtest\tuxconfig
INCLUDE,值为: C:\oracle\product\10.2.0\db_1\OCI\include; C:\Program Files\Microsoft Visual Studio 8\VC\include;
2.系统环境变量
INCLUDE,值为: C:\Program Files\Microsoft Visual Studio 8\VC\include; C:\Program Files\Microsoft Visual Studio 8\VC\atlmfc\include; C:\Program Files\Microsoft Visual Studio\VC98\MFC\Include; C:\Program Files\Microsoft Visual Studio\VC98\Include; C:\Program Files\Microsoft Visual Studio 8\VC\include;
LD_LIBRARY_PATH,值为: $LD_LIBRARY_PATH:$TUXDIR/lib
LIB,值为: C:\Program Files\Microsoft Visual Studio 8\VC\lib; C:\tools\xerces-c_2_3_0-win32\xerces-c_2_3_0-win32\lib; C:\Program Files\Microsoft Visual Studio\VC98\Lib;
path,值为: %TUXDIR%\bin; C:\Program Files\Microsoft Visual Studio 8\Common7\IDE; C:\oracle\product\10.2.0\db_1\BIN; C:\Program Files\Microsoft Visual Studio 8\VC\bin;
TUXDIR,值为:C:\bea\tuxedo9.0
2.2.2 配置的步骤2.2.2.1 ORACLE的配置1.以 dba 的权限进入sqlplus(默认口令是oracle)
C:\>sqlplus / as sysdba
2.搜索一下 xaview.sql 所在的位置(本例是在 C:\oracle\product\10.2.0\db_1\RDBMS\ADMIN\ 下)
运行: SQL>@C:\oracle\product\10.2.0\db_1\RDBMS\ADMIN\xaview.sql;
如果一切正长则会提示创建了两个视图
3.授权 SQL>grant select on v$xatrans$ to public with grant option; SQL>grant select on v$pending_xatrans$ to public with grant option;
4. 用 system 用户(缺省口令是manager,请根据实际情况修改)连接并授权 SQL>connect system/manager; SQL>grant select any table to public;
5. 以system的身份建表,并插入2条测试记录 SQL>create table zwtest (name varchar2(8), age number); SQL>insert into zwtest values('zhang', 30); SQL>insert into zwtest values('liu', 27); SQL>commit;
2.2.2.2 TUXEDO的配置1. 修改 tuxedo 安装路径下的udataobj目录下的RM文件,在以Oracle_XA:xaosw:开头的那行开头加上#注释掉 如果是windows平台,就添加以下行: Oracle_XA;xaosw;C:\oracle\product\10.2.0\db_1\RDBMS\XA\oraxa10.lib C:\oracle\product\10.2.0\db_1\precomp\LIB\orasql10.lib 如果是unix平台,就添加: Oracle_XA:xaosw:-L${ORACLE_HOME}/lib -lclntsh
注意: 上述库文件的位置可能随版本不同而不同,修改时以在本地机器上的实际位置为准
2. 在TUXEDO 用户下创建TMS文件:TMS_ORA10g, TUXEDO通过 TMS_ORA10g 与 ORACLE数据库采用 XA 协议进行通讯 buildtms -o c:\bea\tuxedo9.0\bin\TMS_ORA10g -r Oracle_XA
注意: 1.要是在windows平台下就在命令行窗口中运行,并确保c:\bea\tuxedo9.0\bin已经添加到系统的path环境变量中(可用echo %path% 查看)。 这个过程中有可能会提示找不到一些头文件或库文件,一般都是所缺文件所在路径没有包含在path或INCLUDE或LIB的环境变量中引起的, 可以搜索所缺文件的目录,把这个目录添加到对应的环境变量中。添加完后要打开一个新的命令行窗口才会生效。 2.如果TUXEDO服务端与ORACLE数据库不在同一台服务器上,可能会提示找不到库文件 oraxaX.lib和 orasqlX.lib(文件名中的大写X表示对应 的oracle版本号),可到ORACLE数据库的服务端对应目录下把这两个文件拷到本地机器ORACLE的客户端下的对应目录下。
3. 配置 ubbconfig(1) 在 *MACHINES 中增加:
TLOADDEVICE = "/home/oracle/temp/simpdb/TLOG"TLOGNAME=TLOGTLOGSIZE=200
(2) 改 *GROUPS 的配置为:*GROUPSGROUP1 LMID=simple GRPNO=1OPENINFO="Oracle_XA:Oracle_XA+Acc=P/scott/tiger+SesTm=600+MaxCur=5+LogDir=."TMSNAME="TMS_ORA10g" TMSCOUNT=2
注意:scott/tiger 为《tuxedo 简易培训教程》上数据库所采用的用户及口令,在我的测试平台上导致tuxedo服务启动时 TMS_ORA10g无法启动, 所及建议用 system用户和对应密码 替换 OPENINFO中的 scott/tiger。
如果要试一下 scott 用户, 一般应先以system或sysdba用户登录sqlplus,然后对scott用户进行解锁: alter user scott account unlock; 然后才能以scott用户登录,再根据提示修改默认密码。
修改后的配置文件 ubbconfig 内容如下:*RESOURCESIPCKEY 123456DOMAINID simpappMASTER simpleMAXACCESSERS 100MAXSERVERS 50MAXSERVICES 100MODEL SHMLDBAL N*MACHINESservername LMID=simpleAPPDIR="D:\simapp"TUXCONFIG="D:\simapp\tuxconfig"TUXDIR="C:\bea\tuxedo9.0"TLOGDEVICE="D:\simapp\TLOG"TLOGNAME=TLOGTLOGSIZE=100*GROUPSGROUP1 LMID=simple GRPNO=1OPENINFO="Oracle_XA:Oracle_XA+Acc=P/scott/tiger+SesTm=600+MaxCur=5+LogDir=."TMSNAME="TMS_ORA10g" TMSCOUNT=2*SERVERSDEFAULT: CLOPT="-A"exefilename SRVGRP=GROUP1 SRVID=1*SERVICES
注: 1) *MACHINES下的 servername 是指服务器所在的完整的计算机名
2) exefilename 是服务端可执行程序名,不加后缀,如果写错了在启动tuxedo服务时会出现以下报错: CMDTUX_CAT:816: ERROR: Cannot exec, executable file not found
3) *GROUPS 的 OPENINFO中,如果用scott用户登录,则启动tuxedo服务时会出现以下报错: exec TMS_ORA10g -A : Failed. 用system用户登录则正常,可能和oracle相关的配置有关。但是以 system 用户登录后,在随后 执行客户端示例程序时也会报错: tpcall failed, tperrno=11, tperrtext=TPESVCFAIL - application level service failure查看ULOG文件,提示 select from EMP failure, sqlcode=-942, sqlerr=ORA-00942: 表或视图不存在 然后用system用户登录sqlplus,查询EMP表: select * from EMP;果然提示: ORA-00942: 表或视图不存在 再用scott连接: conn scott/aiuuai;查询EMP表返回正确结果。总结: 用示例程序测试时,要么正确配置 Oracle 使TMS可以通过scott用户连接到oracle,要么以system 用户建新表作为被测的数据表,后者可能更容易些。
4) 在应用配置里提到,*SERVICES 提供了应用的特殊交易的信息。包括负载平衡(LOAD)和数据缓冲类型检查(BUFTYPE)。 如果全部都是缺省值则本节可以省略。所以,*SERVICES下没有内容
(3) 最后生成 tuxconfig:
tmloadcf -y ubbconfig
系统自动生成一个 tuxconfig 文件, -y 的意思是无条件地覆盖已经存在的 tuxconfig 文件。
以下是我定义的 ubbconfig 内容:
*RESOURCESIPCKEY 123456 #<Replace with a valid IPC Key>DOMAINID zwtest MASTER simpleMAXACCESSERS 10MAXSERVERS 5MAXSERVICES 10MODEL SHMLDBAL N
*MACHINESAPPDIR= "D:\zwtest" #"<Replace with the current directory pathname>"TUXCONFIG= "D:\zwtest\tuxconfig" #<Replace with your TUXCONFIG Pathname>"TUXDIR= "C:\bea\tuxedo9.0" #"<Directory where TUXEDO is installed>""HP12193906110" LMID=simpleTLOGDEVICE="D:\zwtest\TLOG"TLOGNAME=TLOGTLOGSIZE=100
*GROUPSGROUP1 LMID=simple GRPNO=1 OPENINFO=NONEOPENINFO="Oracle_XA:Oracle_XA+Acc=P/system/aiuuai+SesTm=600+MaxCur=5+LogDir=."TMSNAME="TMS_ORA10g" TMSCOUNT=2
*SERVERSDEFAULT:CLOPT="-A"testsvr SRVGRP=GROUP1 SRVID=1
*SERVICES
4.重命名下列文件,因为下列文件名与ORACLE带的文件名有冲突,所以要更改(1) tuxedo安装路径 include目录下的:sqlca.h 改为 sqlca.h.bbbsqlcode.h 改为 sqlcode.h.bbbsqlda.h 改为 vsqlda.h.bbb(2) tuxedo安装路径 lib目录下的:libsql.lib 改名为 libsql.lib.bbb
注意: 在oracle10g下,只发现sqlca.h, sqlda.h和tuxedo有重名文件,实际修改时最好先在oracle安装目录中查找 sqlca.h , sqlcode.h , sqlda.h , libsql.lib 这4个文件,如果和tuxedo安装目录下有重名文件,则将tuxedo目录下的重名文件作以上的更名修改
5.用TMADMIN 创建 TLOG文件,TUXEDO用一个文件TLOG记录对数据库操作的日志。用于协调分布式数据库的提交与回滚。D:\>tmadmin>crdl -b 500 -z d:\zwtest\TLOG>crlog -m simple>q
2.2.2.3 服务端的程序:(1) testsvr.pc ,功能:根据客户端传入的EMPNO到表EMP中取ENAME的值,并把它返回给客户端。 但实际运行时会有错误返回,查ULOG发现是将从客户端收到的字符串转换为long型时有误, 因而导致错误的empno,所以查不到对应的ename,oracle查询返回"未找到数据"的错误,进而 使服务端返回交易失败的错误信息
/* testsvr.pc */
#include <stdio.h>#include <atmi.h>#include <userlog.h>
EXEC SQL INCLUDE sqlca;
EXEC SQL BEGIN DECLARE SECTION;
long al_empno=0;
char ac_ename[11]="";
EXEC SQL VAR ac_ename IS STRING(11);
EXEC SQL END DECLARE SECTION;
TEST(TPSVCINFO *rqst){ /* recv data from client */
al_empno = (FBFR32 *)rqst->data;
EXEC SQL select ename into :ac_ename from EMP where empno=:al_empno;
if (sqlca.sqlcode != 0) { userlog ("select from EMP failure, sqlcode=%ld, sqlerr=%s\n", sqlca.sqlcode, (char*)sqlca.sqlerrm.sqlerrmc);
strcpy (rqst->data, sqlca.sqlerrm.sqlerrmc);
tpreturn (TPFAIL, 0, rqst->data, 0, 0); }
/* return the record set to client */ strcpy (rqst->data, ac_ename);
tpreturn (TPSUCCESS, 0, rqst->data, 0, 0);}***************************************************************************************(2) 修改后的 testsvr.c, 经测试可以正常运行,返回结果 并增加了一个将收到的字符串转换为大写并返回的服务(交易) UPPER
/* testsvr.pc */
#include <stdio.h>#include <atmi.h>#include <userlog.h>#include <stdlib.h>
EXEC SQL INCLUDE sqlca;
EXEC SQL BEGIN DECLARE SECTION;
int al_age=0;
char ac_name[11]="";
EXEC SQL VAR ac_name IS STRING(11);
EXEC SQL END DECLARE SECTION;
GETNAME(TPSVCINFO *rqst){ /* recv data from client */ al_age = atoi (rqst->data);
EXEC SQL select name into :ac_name from zwtest where age=:al_age;
if (sqlca.sqlcode != 0) { userlog ("select from help failure, sqlcode=%ld, sqlerr=%s, age=%d\n", sqlca.sqlcode, (char*)sqlca.sqlerrm.sqlerrmc, al_age);
strcpy (rqst->data, sqlca.sqlerrm.sqlerrmc);
tpreturn (TPFAIL, 0, rqst->data, 0, 0); }
/* return the record set to client */ strcpy (rqst->data, ac_name);
tpreturn (TPSUCCESS, 0, rqst->data, 0, 0);}
UPPER(TPSVCINFO *rqst){int i;
userlog("request string = %s\n", rqst->data);
for (i=0; i<rqst->len-1; i++)rqst->data[i] = toupper(rqst->data[i]);
tpreturn (TPSUCCESS, 0, rqst->data, 0L, 0);
2.2.2.4 编译服务端程序1.用ORACLE的 proc 把 testsvr.pc 文件预编译成 testsvr.c 文件 d:\zwtest\proc testsvr.pc include=%TUXDIR%\include
2.用buildserver把第一步生成的 testsvr.c 编译成可执行文件,注意 -r 后带的 Oracle_XA 要与 RM 文件中的一致。 d:\zwtest\buildserver -o testsvr -f testsvr.c -r Oracle_XA -s GETNAME, UPPER
2.2.2.5 编写客户端程序:(1) testcli.c, 发送一个字符串给服务端,接收服务端传回的转换为大写的字串
/* testcli.c */
#include <stdio.h>#include <string.h>#include "atmi.h"
int main (int argc, char *argv[]){ long reqlen = 1024;
char *reqbuf;
if (argc != 2) { printf ("usage: testcli string\n"); exit (0); }
/* connect to tuxedo server */if (tpinit ((TPINIT *) NULL) == -1) { (void) fprintf (stderr, "Tpinit failed\n");
exit (1); }
/* allocate send buffer */ reqbuf = (char *) tpalloc ("STRING", NULL, reqlen);
if (reqbuf == (char *)NULL) { printf("tpalloc failed\n"); tpterm(); }
strcpy (reqbuf, argv[1]);printf("reqbuf = %s\n", reqbuf);
/* call server "UPPER" of tuxedo */ if (tpcall ("UPPER", (char *)reqbuf, 0L, (char**)&reqbuf, (long *)&reqlen, 0 ) < 0) { printf ("tpcall failed, tperrno=%ld, tperrtext=%s\n", tperrno, tpstrerror(tperrno));
tpfree (reqbuf);
tpterm ();
exit (1); }
printf ("return = %s\n", reqbuf);
tpfree (reqbuf);
tpterm ();
return (0);}****************************************************************************(2) testdbcli.c,传递一个年龄值给服务端,服务端查oracle数据库后返回对应的姓名
/* testdbcli.c */
#include <stdio.h>#include <string.h>#include "atmi.h"
int main (int argc, char *argv[]){ char *reqbuf; int reqlen = 11;
if (argc != 2) { printf ("usage: testdbcli age_number\n"); exit (0); } /* connect to tuxedo server */if (tpinit ((TPINIT *) NULL) == -1) { (void) fprintf (stderr, "Tpinit failed\n");
exit (1); }
/* allocate send buffer */ reqbuf = (char *) tpalloc ("STRING", NULL, reqlen);
if (reqbuf == (char *)NULL) { printf("tpalloc failed\n"); tpterm(); }
memset(reqbuf, 0, reqlen);strcpy(reqbuf, argv[1]);
printf("reqbuf = %s\n", reqbuf);
/* call server "GETNAME" of tuxedo */ if (tpcall ("GETNAME", (char *)reqbuf, 0L, (char**)&reqbuf, (long *)&reqlen, 0 ) < 0) { printf ("tpcall failed, tperrno=%ld, tperrtext=%s\n", tperrno, tpstrerror(tperrno));
tpfree (reqbuf);
tpterm ();
exit (1); }
printf ("name = %s\n", reqbuf);
tpfree (reqbuf);
tpterm ();
return (0);}
2.2.2.6 编译客户端程序
d:\zwtest\buildclient -o testcli -f testcli.c d:\zwtest\buildclient -o testdbcli -f testdbcli.c
2.2.2.7 启动 tuxedo d:\zwtest\tmboot -y
如果显示提示信息:
Booting all admin and server processes in D:\zwtest\tuxconfigINFO: BEA Tuxedo, Version 9.0, 32-bit, Patch Level (none)INFO: Serial #: 650522264138-1796918373125, Expiration 2006-01-15, Maxusers 100INFO: Licensed to: BEA Evaluation Customer
Booting admin processes ...
exec BBL -A : process id=3960 ... Started.
Booting server processes ...
exec TMS_ORA10g -A : process id=2692 ... Started.exec TMS_ORA10g -A : process id=2588 ... Started.exec testsvr -A : process id=2872 ... Started.4 processes started.
就说明服务正确启动了, 这时就可以在客户端所在目录下运行客户端程序:
D:\zwtest>testcli.exe helloreqbuf = helloreturn = HELLO
D:\zwtest>testdbcli.exe 30reqbuf = 30name = zhang
如果提示:
Booting all admin and server processes in D:\zwtest\tuxconfigINFO: BEA Tuxedo, Version 9.0, 32-bit, Patch Level (none)INFO: Serial #: 650522264138-1796918373125, Expiration 2006-01-15, Maxusers 100INFO: Licensed to: BEA Evaluation Customer
Booting admin processes ...
exec BBL -A : process id=3920 ... Started.
Booting server processes ...
exec TMS_ORA10g -A : Failed.exec TMS_ORA10g -A :
并且程序停止不动,也不退出,好像死了一样
这就是TMS_ORA10g 在启动时发生了错误,本例中是由于前面提到的OPENINFO中使用scott用户引起的,这样就会在当前目录生成一个 *.trc 文件,记录失败的原因。同时 tuxedo 的 ULOG.MMDDYY 文件中也会记录一些错误信息,以供进行错误分析。
假死的程序可以用 Ctrl+C 来终止,然后用 tmshutdown -y 来关闭已经启动的 BBL 和其他服务。最后可以用 tmshutdown -y来检测所有服务是否已关闭,提示:Shutting down all admin and server processes in D:\zwtest\tuxconfig
tmshutdown: internal error: CMDTUX_CAT:764: ERROR: can't attach to BB就表示本机的服务已经被关闭,这时就可以去修改ubbconfig,重新生成tuxconfig,然后再启动服务。需要对服务端程序进行修改时,也必须先tmshutdown -y,才能修改服务端程序并重新生成可执行程序。
=============================================================
折磨我两天的 tuxedo buildserver 编译服务启动挂起问题终于解决,不容易啊,为了让有过类似经历的人省下点时间,现记录如下:故障现象:准备将原系统 redflag4.0+tuxedo8.0+oracle 8.1.7的系统移植到redfalg5.0+tuxedo8.1+oracle10g开发环境:proc,gcc3.4.6好,部署软件环境,修改环境变量,更改tuxedo的某些oracle的头文件,如slqda.h等...在此不详细说明,网上有不少相关文档,可以查看.经过一番折腾,buildserver终于将服务编译通过,happy!go on!tmboot -y..........CMDTUX_CAT:819: INFO: Process id=16218 Assume started (pipe).查看ULOG,一些扯淡的话142508.kaifa!BBL.14662.3086919904.0: 09-03-2004: Tuxedo Version 8.1, 32-bit, Patch Level 099142508.kaifa!BBL.14662.3086919904.0: LIBTUX_CAT:1434: ERROR: Invalid trace specification; ignored142508.kaifa!BBL.14662.3086919904.0: LIBTUX_CAT:1434: ERROR: Invalid trace specification; ignored142508.kaifa!BBL.14662.3086919904.0: LIBTUX_CAT:577: ERROR: Unable to register because the slot is already owned by another process142508.kaifa!BBL.14662.3086919904.0: LIBTUX_CAT:248: ERROR: System init function failed, Uunixerr =142508.kaifa!BBL.14662.3086919904.0: CMDTUX_CAT:26: INFO: The BBL is exiting system............142508.kaifa!GWADM.14726.3086341824.0: LIBTUX_CAT:262: INFO: Standard main starting142508.kaifa!DMADM.11747.3086805376.0: CMDGW_CAT:3250: ERROR: Cannot send config to GWADM group=LDMGRP_1142508.kaifa!GWADM.14726.3086341824.0: LIBTUX_CAT:250: ERROR: tpsvrinit() failed没用,继续找tpsvrinit中连接数据库hang,问题就出在这这个环境没有用xa连接,直接EXEC SQL CONNECT好,拿sqlplus手工连接测试,没问题阿。那好,直接写个带proc连接数据库的干净的(不加载一些乱七八糟的库)可执行文件,测试,成功。那用buildclient写个可执行文件,测试,成功。那就是buildserver不行阿 ,好,拿tuxedo提供的sample编译个服务,测试,失败。原来跟我没关系阿,就是tuxedo和oracle之间的问题了上网goooooooooooooogle不好找阿,好不容易有点感觉了,得出猜测:tuxedo8.1和oracle10g 某些库冲突,tuxedo8.1 需要打补丁,(tuxedo9.1也有这中情况),可是这个补丁就是找不到阿,快崩溃了期间请教了n个师傅无果,无意中又找到n+1个师傅,终于.......问题出在这 ;libclntsh.so.10.1,记住这个so$ORACLE_HOME/lib下有这个动态链接库同样/usr/lib下也有这个动态库,删掉,问题解决。但是有点疑问,环境变量写死指向ORACLE的库了,ldd 可执行文件 也指向了ORACLE的库了,虽说/usr/lib下的优先级高,但是可执行文件在运行加载动态库时怎么找到/usr/lib下的冲突的这个库libclntsh.so.10.1的呢