使用OCCI交互CLOB

来源:互联网 发布:spss数据分析简单案例 编辑:程序博客网 时间:2024/05/17 23:06

前言

            这篇文章是《Weblogic与Tuxedo互连指南》的延续,Tuxedo是交易中间件,我手上的项目是用来接受请求后再转发到另一个Tuxedo中的环境模式。中心转发时需要记录日志以及一些业务逻辑处理,需要与数据库交互,中心是用c++写的,使用的occi与Oracle连接。数据传递使用XML。那么现在问题来了,当客户端传递大xml到中心时,Tuxedo服务进程就died。我是Java程序员,在这之前对c++只有HelloWorld的接触,指针也只是听说过。各种调试后找到了服务died的原因,原因在于与数据库交互时,数据量大的原因,导致服务挂起,数据库过程定义入参是clob,但在c++里面set的string,好吧,以上全是环境铺垫,下面进入正题,occi与oracle的clob传入及传出。

步骤

1、定义Oracle过程,传入和传出都使用CLOB

2、编写C++代码调用Oracle过程,实现CLOB传入及传出

实现Oracle部分

1、建表

create table TESTCLOB(  CID       NUMBER(38),  DETAIL    CLOB,  WRITEDATE DATE);
2、建过程

CREATE OR REPLACE PACKAGE Pkg_test IS   PROCEDURE p_test_clob(prm_input    IN   CLOB,     --传入                         prm_output   OUT  CLOB,     --传出                         prm_lengthb  OUT  INTEGER); --传出长度END Pkg_test;CREATE OR REPLACE PACKAGE BODY Pkg_test ISPROCEDURE p_test_clob(prm_input    IN   CLOB,   -- 传入                      prm_output   OUT  CLOB,   -- 传出                      prm_lengthb  OUT  INTEGER)-- 传出长度AS   clob_buffer  CLOB;      --缓冲区   input        CLOB;      --input分段   n_out        VARCHAR2(100);   n_length     INTEGER;   input_length INTEGER;   --input长度   base_length  INTEGER;   --基本分段的长度   index_length INTEGER;BEGIN   prm_lengthb := 0;       --初始化传出长度为0   base_length := 16383;   --每段长度16383   index_length := 16383;  --第一段长度16383      /* 写入处理 */   --1、清空clob字段   update testclob      set detail = empty_clob()    where cid = '1';       --2、将clob写给缓冲区   select detail     into clob_buffer     from testclob    where cid = '1';       --3、截取input,一次写入过大会报错,故截取多次写入   input_length := DBMS_LOB.getlength(prm_input);   input := dbms_lob.substr(prm_input,base_length,1);   --4、写入第一段   DBMS_LOB.OPEN(clob_buffer, DBMS_LOB.LOB_READWRITE);   DBMS_LOB.WRITE(clob_buffer, DBMS_LOB.getlength(input), 1, input);   --5、如果input超过第一段长度就分段截取写入,每次16383   while input_length > index_length loop      input := dbms_lob.substr(prm_input,base_length,index_length);      index_length := index_length + base_length;      DBMS_LOB.WRITEAPPEND(clob_buffer,DBMS_LOB.getlength(input), input);   end loop;   --6、写入表字段   update testclob      set detail = clob_buffer    where cid = '1';      --7、关闭缓存区   DBMS_LOB.CLOSE(clob_buffer);      /*  传出处理  */   --1、创建临时空间   dbms_lob.createtemporary(prm_output, true);   --2、往prm_output写入‘Hi,你好’,200次   n_out := 'Hi,你好!';   --3、关键点,获取字节长度,C++中使用   n_length := lengthb(n_out);   for i in 1..200 loop      dbms_lob.writeappend(prm_output, length(n_out), n_out);      --4、累加写入长度      prm_lengthb := prm_lengthb + n_length;   end loop;   END p_test_clob;END Pkg_test;

实现C++部分

#include "stdafx.h"#include <iostream>#include <occi.h>using namespace std;using namespace oracle::occi;#pragma comment (lib, "C:\\oracle\\product\\10.2.0\\db_1\\OCI\\lib\\MSVC\\oraocci10.lib")int main(){   Environment *env=Environment::createEnvironment(Environment::DEFAULT);   string name = "test";   string pass = "test";   string srvName = "192.168.43.1:1521/orcl";   string lstr_input = "HelloWorld";   Statement *stmt;   try{   //1、连接数据库   Connection *conn = env->createConnection(name, pass,srvName);   cout<<"conn success"<<endl;   //2、执行一个oracle方法,创建clob的临时空间,与oracle过程里面的用法一致   stmt = conn->createStatement("begin dbms_lob.createtemporary(:p1,FALSE);end;");   stmt->registerOutParam(1,OCCICLOB);   stmt->executeUpdate();   //3、取出上一步的对象   Clob clob_input = stmt->getClob(1);   //4、写入字符传到clob   clob_input.write((unsigned int)lstr_input.size(),    (unsigned char*)lstr_input.c_str(),(unsigned int)lstr_input.size());   conn->terminateStatement (stmt);   //5、调用业务过程   stmt = conn->createStatement("BEGIN Pkg_test.p_test_clob(:v1,:v2,:v3); END;");   stmt->setClob(1,clob_input);  //传入包含字符串的clob   stmt->registerOutParam(2,OCCICLOB);   stmt->registerOutParam(3,OCCIINT);   stmt->executeUpdate ();      //6、取出clob   Clob clob_ouput = stmt->getClob(2);   //返回的字符数   unsigned int cloblen = clob_ouput.length();       //7、分配空间用于存储返回的clob中的字符   //   空间大小为过程返回的第3个参数,即过程中累加的字节数   char *chr_out = (char *) malloc(stmt->getInt(3));   //8、设置字符类型,避免中文乱码   clob_ouput.setCharSetForm(OCCI_SQLCS_IMPLICIT);   //9、读取clob中的数据到内存空间   clob_ouput.open(OCCI_LOB_READONLY);   clob_ouput.read(cloblen*2, (unsigned char*)chr_out, cloblen*2, 1);     clob_ouput.close();   //10、重要的一步,调试了几天才明白,char的结尾加'\0'   //    关键是结尾的位置不是cloblen的字符长度,而是过程返回的字节长度   //    Java中没有这些问题,纠结了好长时间。没有'\0'结尾时读取的值最后   //    有乱码,若给的下标位置没正确,则读取的字符被截断   chr_out[stmt->getInt(3)]='\0';   string str_ouput = chr_out;   cout<<str_ouput.c_str()<<endl;     int j;   cin>>j;   conn->terminateStatement (stmt);       env->terminateConnection(conn);   }   catch(SQLException e)   {      cout<<e.what()<<endl;      return -1;   }   Environment::terminateEnvironment(env);   cout<<"end!"<<endl;   return 0;}

测试


若没有chr_out[stmt->getInt(3)]='\0';,则最后有乱码

若'\0’赋值的下标不对,则数据被截取

0 0
原创粉丝点击