发现自从2008年oracle收购bea后,TUXEDO交易中间件的文章是越来越少了,感觉oracle并没有把它很好的发扬光大,然而我们公司会一直使用它,因为它的确太优秀,几乎所有核心系统、重要系统都使用它,公司内部对它都很熟悉,而且世界500强很多企业也在用它,所以,在学习了之后,本人把一个范例在这里分享。也希望对一些tuxedo爱好者有所帮助。
题目:
编写一个TUXEDO服务端程序,要求提供如下服务: 对客户端传送过来的数据进行处理,在数据格式正确的情况下插入到scott用户的dept表中,并给客户端应答。同时编写一个客户端程序,以命令行参数的形式传送需要插表的数据。 如:运行客户端程序: ./clientinsert 15 fred nanning 则15 fred nanning这3个值将插入数据库中,并且根据处理结果显��:插入成功或者失败。
本例环境:redflag DC server 5.0 + TUXEDO10gR3 + oracle10g
需要对oracle自带用户scott解锁,本例使用scott用户的相关表和应用用户hwt作为范例。
说明:#打头的命令表明以root用户执行,$打头的是以应用用户或者oracle用户执行。
有疑问可以加我QQ:68053651 欢迎交流
一、ORACLE配置
Oracle用户下,用sysdba帐户登陆数据库,
SQL> conn / as sysdba
SQL> @$ORACLE_HOME/rdbms/admin/xaview.sql
DROP VIEW v$xatrans$
*
ERROR at line 1:
ORA-00942: table or view does not exist
DROP VIEW v$pending_xatrans$
*
ERROR at line 1:
ORA-00942: table or view does not exist
View created.
View created.
SQL> grant select on v$xatrans$ to public with grant option;
Grant succeeded.
SQL> grant select on v$pending_xatrans$ to public with grant option;
Grant succeeded.
SQL> grant select any table to public;
Grant succeeded.
SQL>alter user scott account unlock;
SQL> grant dba to scott; //此步也许不是合理的解决方法,dba权限不该轻易给应用用户,看看还有什么方法可以代替的(网上说增加select 权限,但本人尝试未成功)。
在$ORACLE_HOME/precomp/admin/pcscfg.cfg中的sys_include里添加如下内容:/opt/app/oracle/product/10.2.0/db_1/precomp/public
二、重命名下列文件,因为下列文件名与ORACLE带的文件名有冲突,所以要改名。
(1)TUXEDO安装路径include目录下的下面文件
#mv sqlca.h sqlca.h.bbb
#mv sqlcode.h sqlcode.h.bbb
#mv sqlda.h sqlda.h.bbb
(2)重命名TUXEDO安装路径lib目录下的下面文件 (如果文件不存在可忽略)
mv libsql.lib libsql.lib.bbb
(3)重命名/usr/lib下的文件
mv libclntsh.so.10.1 libclntsh.so.10.1.bbb
三、TUXEDO的配置
1、修改$TUXDIR/udataobj/RM文件(TUXEDO10gR3不用做此步骤)
把原来的以Oracle_XA:xaosw:开头的屏蔽掉、
添加Oracle_XA:xaosw:-L${ORACLE_HOME}/lib -lclntsh
确保应用用户能够访问$ORACLE_HOME,同时把应用用户加入oracle的oinstall组(root用户执行)
#. /home/oracle/.bash_profile
#chmod -R 755 $ORACLE_HOME
#usermod -G oinstall -g hwt hwt
然后将oracle用户的.bash_profile内容添加至应用用户的.bash_profile
即,hwt的.bash_profile内容为(请根据自己机器进行配置,建议以root用户在vi里用命令:r /home/oracle/.bash_profile的方式导入文本):
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
# added by oranavi
export ORACLE_BASE=/opt/app/oracle
export ORACLE_HOME=/opt/app/oracle/product/10.2.0/db_1
export ORACLE_SID=testdb
export NLS_LANG="Simplified Chinese_CHINA.ZHS16GBK"
export ORA_NLS33=$ORACLE_HOME/ocommon/nls/admin/data
export PATH=$PATH:$ORACLE_HOME/bin
export ORACLE_DOC=$ORACLE_HOME/doc
CLASSPATH=$ORACLE_HOME/jre:$ORACLE_HOME/JRE
CLASSPATH=$CLASSPATH:$ORACLE_HOME/jlib
CLASSPATH=$CLASSPATH:$ORACLE_HOME/rdbms/jlib
CLASSPATH=$CLASSPATH:$ORACLE_HOME/jdbc/lib/classes12.jar
CLASSPATH=$CLASSPATH:$ORACLE_HOME/jdbc/lib/nls_charset12.jar
export CLASSPATH
LD_LIBRARY_PATH=$ORACLE_HOME/lib:$ORACLE_HOME/ctx/lib
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$ORACLE_HOME/jdbc/lib
export LD_LIBRARY_PATH
unset LANG
ulimit -n 65536 > /dev/null 2>&1
ulimit -u 16384 > /dev/null 2>&1
PATH=$PATH:$HOME/bin
export PATH
unset USERNAME
设置环境变量
ORACLE_HOME=/opt/app/oracle/product/10.2.0/db_1;export ORACLE_HOME
TUXDIR=/tuxedo10/tuxedo10gR3;export TUXDIR
APPDIR=/home/hwt/tuxint;export APPDIR
export PATH=.:$ORACLE_HOME:$ORACLE_HOME/bin:$TUXDIR/bin:$APPDIR:$PATH
TUXCONFIG=$APPDIR/tuxconfig;export TUXCONFIG
LD_LIBRARY_PATH=$ORACLE_HOME/lib:$TUXDIR/lib;export LD_LIBRARY_PATH
FIELDTBL32=fmlfile;export FIELDTBL32
FLDTBLDIR32=$APPDIR;export FLDTBLDIR32
生效环境变量:
. ./setenv.sh
创建TMS文件:TMS_ORA,TUXEDO通过TMS_ORA与ORACLE数据库采用XA协议进行通讯
#chmod -R 755 $TUXDIR(这里注意如果$TUXDIR没有生效 需要写绝对路径)
$buildtms -o $TUXDIR/bin/TMS_ORA -r Oracle_XA
配置ubb
*RESOURCES
IPCKEY 210451
DOMAINID simpapp
MASTER simple
MAXACCESSERS 10
MAXSERVERS 20
MAXSERVICES 30
MODEL SHM
LDBAL N
SCANUNIT 10
BLOCKTIME 5
*MACHINES
DEFAULT:
APPDIR="/home/hwt/tuxint"
TUXCONFIG="/home/hwt/tuxint/tuxconfig"
TLOGNAME=TLOG
TUXDIR="/tuxedo10/tuxedo10gR3"
TLOGDEVICE="/home/hwt/tuxint/TLOG"
TLOGSIZE=150
localhost LMID=simple
*GROUPS
GROUP1
LMID=simple GRPNO=1 OPENINFO=NONE
ORAGRP
LMID=simple GRPNO=5
OPENINFO="Oracle_XA:Oracle_XA+Acc=P/scott/scott+SesTm=120+SqlNet=testdb+LogDIR=."
CLOSEINFO=""
TMSNAME=TMS_ORA TMSCOUNT=5
*SERVERS
DEFAULT:
CLOPT="-A"
svrInsert SRVID=10 SRVGRP=ORAGRP
*SERVICES
#INSERT
编译ubb:
$tmloadcf -y ubb
6、
创建TLOG:
tmadmin<<!
crdl -b 300 -z "/home/hwt/tuxint/TLOG"
crlog -m simple
!
这里300一般为TLOGSIZE两倍左右
fmlfile:
*base 500
DEPTNO 1 long - -
DNAME 2 string - -
LOC 3 string - -
客户端程序clientinsert:
#include <stdio.h>
#include "atmi.h"
#include "fml32.h"
#include "userlog.h"
#include "fmlfile.h"
int main(int argc, char *argv[])
{
if (argc != 4) {
(void) fprintf(stderr, "usage:%s value1 value2 value3\n", argv[0]);
(void) exit(1);
}
if((strlen(argv[1])>2) (strlen(argv[2])>13) (strlen(argv[1])>12)){
fprintf(stderr,"input string too long!\n");
exit(1);
}
FBFR32 *pF32, *pF32rec;
long len;
if (tpinit((TPINIT *) NULL) == -1) {
(void) fprintf(stderr,
"Failed to join application -- %s\n",
tpstrerror(tperrno));
(void)
userlog
("Clientfml failed to join application -- %s\n",
tpstrerror(tperrno));
(void) exit(1);
}
if ((pF32 = (FBFR32 *) tpalloc("FML32", NULL, 1024)) == NULL) {
(void) fprintf(stderr,
"Failure to allocate FML32 buffer -- %s\n",
tpstrerror(tperrno));
(void)
userlog
("Clientfml failed to allocate FML32 buffer -- %s\n",
tpstrerror(tperrno));
(void) tpterm();
(void) exit(1);
}
if ((pF32rec = (FBFR32 *) tpalloc("FML32", NULL, 1024)) == NULL) {
(void) fprintf(stderr,
"Failure to allocate FML32 buffer -- %s\n",
tpstrerror(tperrno));
(void)
userlog
("Clientfml failed to allocate FML32 buffer -- %s\n",
tpstrerror(tperrno));
(void) tpterm();
(void) exit(1);
}
int v = atoi(argv[1]);
if (Fchg32(pF32, DEPTNO, -1, (char *) &v, (FLDLEN32) 0) == -1) {
(void) fprintf(stderr,
"Failure to change DEPTNO field -- %s\n",
Fstrerror32(Ferror32));
(void)
userlog
("Clientfml failed to change DEPTNO field -- %s\n",
Fstrerror32(Ferror32));
(void) tpfree((char *) pF32);
(void) tpfree((char *) pF32rec);
(void) tpterm();
(void) exit(1);
}
if (Fchg32(pF32, DNAME, -1, (char *) argv[2], (FLDLEN32) 0) == -1) {
(void) fprintf(stderr,
"Failure to change DNAME field -- %s\n",
Fstrerror32(Ferror32));
(void)
userlog
("Clientfml failed to change DNAME field -- %s\n",
Fstrerror32(Ferror32));
(void) tpfree((char *) pF32);
(void) tpfree((char *) pF32rec);
(void) tpterm();
(void) exit(1);
}
if (Fchg32(pF32, LOC, -1, (char *) argv[3], (FLDLEN32) 0) == -1) {
(void) fprintf(stderr,
"Failure to change LOC field -- %s\n",
Fstrerror32(Ferror32));
(void)
userlog
("Clientfml failed to change LOC field -- %s\n",
Fstrerror32(Ferror32));
(void) tpfree((char *) pF32);
(void) tpfree((char *) pF32rec);
(void) tpterm();
(void) exit(1);
}
if (tpcall
("INSERT", (char *) pF32, 0, (char **) &pF32rec, (long *) &len,
0) == -1) {
(void) fprintf(stderr, "插入失败!\n");
tpstrerror(tperrno);
(void)
userlog
("Clientfml failed to call the INSERT service -- %s \n",
tpstrerror(tperrno));
(void) tpfree((char *) pF32);
(void) tpfree((char *) pF32rec);
} else {
fprintf(stderr, "插入成功!\n");
//FLDLEN32 len2;
int deptno;
char dname[15];
char loc[14];
//len2 = (FLDLEN32) sizeof(deptno);
if(-1==Fget32(pF32rec, DEPTNO, 0, (char *) &deptno, NULL)){
fprintf(stderr,"err in Fget32--deptno\n");
exit(3);
}
//len2 = (FLDLEN32) sizeof(dname);
if(-1==Fget32(pF32rec, DNAME, 0, (char *) dname, NULL)){
fprintf(stderr,"err in Fget32--dname\n");
exit(3);
}
//len2 = (FLDLEN32) sizeof(loc);
if(-1==Fget32(pF32rec, LOC, 0, (char *) loc, NULL)){
fprintf(stderr,"err in Fget32--loc\n");
exit(3);
}
fprintf(stdout, "received the server's reply:\n");
fprintf(stdout, "%d\n%s\n%s\n", deptno, dname, loc);
}
(void) tpfree((char *) pF32);
(void) tpfree((char *) pF32rec);
(void) tpterm();
exit(0);
}
服务端程序svrInsert.pc:
#include <stdio.h>
#include "atmi.h"
#include "fml32.h"
#include "userlog.h"
#include "fmlfile.h"
#include "sqlca.h"
//EXEC SQL INCLUDE sqlca;
EXEC SQL BEGIN DECLARE SECTION;
int deptno;
char dname[15];
char loc[14];
EXEC SQL END DECLARE SECTION;
tpsvrinit(int argc, char *argv[])
{
argc = argc;
argv = argv;
userlog("Welcome to the simple server");
if (tpopen() == -1) {
userlog("connect to Oracle error\n");
return -1;
} else
userlog("connect to Oracle normal\n");
if (sqlca.sqlcode != 0) {
userlog("%d:%-70s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
tpreturn(TPFAIL, 0, NULL, 0, 0);
}
return (0);
}
INSERT(TPSVCINFO * rqst)
{
FBFR32 *pfBuf;
//FLDLEN32 len;
pfBuf = (FBFR32 *) rqst->data;
//len = (FLDLEN32) sizeof(deptno); 反复使用同一个len做Fget32要小心
Fget32(pfBuf, DEPTNO, 0, (char *) &deptno, NULL);
//len = (FLDLEN32) sizeof(dname);
Fget32(pfBuf, DNAME, 0, (char *) dname, NULL);
//len = (FLDLEN32) sizeof(loc);
Fget32(pfBuf, LOC, 0, (char *) loc, NULL);
userlog("\ndeptno=%d\ndname=%s\nloc=%s\n",deptno,dname,loc);
tpbegin(10, 0);
EXEC SQL INSERT INTO dept VALUES(:deptno,:dname,:loc);
if (sqlca.sqlcode != 0) {
userlog("%d:%-70s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
tpreturn(TPFAIL, 0, NULL, 0, 0);
}
tpcommit(0);
tpreturn(TPSUCCESS, 0,(char *)rqst->data, 0L, 0);
}
void tpsvrdone()
{
if (tpclose() == -1) {
userlog("disconnect to Oracle error\n");
return;
}
}
用Makefile编译 :
PC=proc
CC=gcc
CFLAGS=-I${ORACLE_HOME}/precomp/public -I${TUXDIR}/include -L$(ORACLE_HOME)/lib -L$(TUXDIR)/lib #-lclntsh -lecpg
PCFLAGS=include=${ORACLE_HOME}/precomp/public include=${TUXDIR}/include sqlcheck=none ltype=none parse=none
TUXCOF=tuxconfig
FILES=fmlfile.h
.SUFFIXES: .pc .c .o
.pc.c:
$(PC) $(PCFLAGS) $<
.c.o:
$(CC) $(CFLAGS) -c $<
.pc.o:
$(PC) $(PCFLAGS) $<
$(CC) $(CFLAGS) -c $(<:.pc=.c)
DEST = svrInsert \
clientinsert
INTERIM=$(DEST:=.o.c)
all: $(FILES) $(TUXCOF) $(DEST)
tuxconfig: ubb
tmloadcf -y ubb
fmlfile.h: fmlfile
mkfldhdr32 fmlfile
clientinsert: clientinsert.o
buildclient -o clientinsert -f clientinsert.o -v
svrInsert:svrInsert.o
buildserver -v -o svrInsert -f svrInsert.o -s INSERT -r Oracle_XA
clean:
-rm -f $(DEST) $(FILES) $(TUXCOF) *.o tp* svrInsert.c
使用make命令编译即可。
最后说明一下,关于环境变量的配置,可能不一定能够考虑周全,至少本人机器上是通过的,如果找不到命令,一般是环境变量问题,熟悉linux的操作的应该可以自行解决。