使用OCCI交互CLOB

前言

            这篇文章是《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 IS
PROCEDURE 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
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值