摘要 通过一个实例介绍使用VB和Oracle9i plsql的管道技术,制作进度条来反应存储过程执行的实际进度。
关键词 Oracle,VB,进度条,存储过程
在Oracle数据库实际应用过程中,经常把业务处理逻辑的放在存储过程,客户端通过VB中的ADO进行调用。有些业务逻辑处理量大并且复杂,使客户端调用存储过程后,长时间没有反应,也不知存储过程运行状态。本文将通过实例讲解此问题。
一、技术细节
实现原理是利用plsql提供的dbms_pipe包的功能。它提供了多进程之间管道通信的方法,且同一个数据库的两个独立会话之间可以通过管道进行通信。
具体的实现方法是在服务器端定义两个存储过程。一个负责主要处理主要的业务逻辑。
VB客户端调用它的时候,它首先根据自己的业务处理量确定当前的进度值。然后建立有名管道,管道的发送端和接受端都有相应的缓冲器进行接受和发送处理,接着把当前的进度值打包后放入管道中发送。而另一个存储过程则负责解析来读取管道中的存放的进度值。在VB客户端,制作一个定时器,每隔一段时间调用该存储过程,读取这个进度值反应在客户端的画面上。
二.程序实现
首先,以SYS用户登录到Oracle数据库。然后对PRTO用户授予执行dbms_pipe包的权限。执行语句如下:
SQL>grant execute on dbms_pipe to prto;
然后,为了模拟一个复杂事务,在该用户下,建立一个Bonus的表,有ename和job两个列。接着,建立如下的主存储过程读取这个表的记录。每读取一定数量的记录就发送进度值到管道中。创建语句如下:
CREATE OR REPLACE PROCEDURE MAIN
( P_pipename IN VARCHAR2, --传输信息的管道名
P_intflg IN OUT NUMBER)
IS
cursor c1 is
select ename,job
from bonus;
v_ename varchar2(10);
v_job varchar2(9);
V_TOTAL_NUM NUMBER; --记录数
V_REC_NUM NUMBER; --进度条的间隔记录值
V_PROCESS_NUM number :=0;
BEGIN
--读取记录件数
select count(*)
into V_TOTAL_NUM
from bonus;
--设置进度条,将进度条分成10份
IF MOD(V_TOTAL_NUM,10) = 0 THEN
V_REC_NUM := V_TOTAL_NUM / 10;
ELSE
V_REC_NUM := ROUND(V_TOTAL_NUM / 10);
END IF;
open c1;
loop
fetch c1 into v_ename,v_job;
exit when c1%notfound;
--设置进度
IF MOD(c1%ROWCOUNT,V_REC_NUM) = 0 THEN
V_PROCESS_NUM := V_PROCESS_NUM + 10;
IF V_PROCESS_NUM < 100 THEN
DBMS_PIPE.purge(p_pipename); --清除原管道信息
DBMS_PIPE.pack_message(V_PROCESS_NUM); --将进度值压缩
P_intflg :=DBMS_PIPE.send_message(P_pipename); --把压缩信息放入缓冲区
END IF;
END IF;
end loop;
IF c1%rowcount > 0 THEN
DBMS_PIPE.purge(p_pipename);
DBMS_PIPE.pack_message(100);
P_intflg :=DBMS_PIPE.send_message(P_pipename);
END IF;
close c1;
P_intflg := 0;
END;