数据库

本类阅读TOP10

·SQL语句导入导出大全
·SQL Server日期计算
·SQL语句导入导出大全
·SQL to Excel 的应用
·Oracle中password file的作用及说明
·MS SQLServer OLEDB分布式事务无法启动的一般解决方案
·sqlserver2000数据库置疑的解决方法
·一个比较实用的大数据量分页存储过程
·如何在正运行 SQL Server 7.0 的服务器之间传输登录和密码
·SQL中两台服务器间使用连接服务器

分类导航
VC语言Delphi
VB语言ASP
PerlJava
Script数据库
其他语言游戏开发
文件格式网站制作
软件工程.NET开发
使用Oracle实现实时通信

作者:未知 来源:月光软件站 加入时间:2005-2-28 月光软件站

  由于Oracle不提供用于实时输出消息的工具, Oracle数据库开发者总是要面临实时监视他们的储备过程执行的挑战。他们必须使用dbms_output.put_line调用,这个调用直到过程完成才返回结果。

  在本文中,我想演示如何从Oracle8i数据库直接发送电子邮件,作为一种实时通信解决方案。这样我们要监视存储过程就不再需要等待它们完成了,这样的方法还为开发者提供了其他的一些好处:

   . 可以在几分钟内调试一些很长的批处理过程,而不需要等几个小时;

   . 计算用于指定代码块所需的执行时间;

  这就需要解决一个问题,我们如何从运行的存储过程中输出消息以便我们可以即时检查它们,即使我们不在办公场所?我们的做法是把所有必需的过程与函数包装在自定义的包中,然后使用Oracle8i UTL_SMTP包直接地从Oracle数据库中发送电子邮件。下面我将详细讲解一些这个过程。

  Oracle的UTL_SMTP包

  在Oracle8i中引入了UTL_SMTP包(SMTP代表Simple Mail Transfer Protocol简单邮件传送协议,使用TCP端口25在客户机和服务器之间建立通信联络),使开发者能够从数据库发送电子邮件。

  只有安装带有Java虚拟机(JVM)的8i或更高的版本才能使用UTL_SMTP。 此外还必须把plsql.jar载入数据库中。否则,当调用UTL_SMTP API来发送电子邮件的时候我们将得到下面的异常:ORA - 29540 : class oracle/plsql/net/TCPConnection does not exist。

  默认的$ORACLE_HOME/javavm/install/initjvm.sql脚本(安装了JVM)不运行把plsql.jar载入数据库的initplsj.sql脚本。系统用户或者内部用户可以手工运行$ORACLE_HOME/RDBMS/ADMIN/initplsj.sql脚本以解决这个问题。 如果你没有可用的脚本,你要么可以从Oracle支持那里得到它,要么可以简单地直接使用loadjava载入实用程序plsql.jar:

  loadjava -user sys/password@database -resolve plsql/jlib/plsql.jar

  UTL_SMTP API:

  本文的代码中使用了下列UTL_SMTP包中的API:

   OPEN_CONNECTION():打开到简单邮件传送协议服务器的连接。

   HELO():执行连接之后建立与简单邮件传送协议服务器初始的收发关系功能,它能识别发送到服务器的“信使”。

   MAIL():初始化与服务器的邮件交换,但是事实上不发送消息。

   RCPT():识别消息的接受者。为了把一条消息发送到多个接受者,你必须多次调用这个过程。

   DATA():指定电子邮件的内容。

   QUIT():终止一个SMTP会话并且断开与服务器的连接。

  为了利用应用程序编程接口,把下面的调用按照给定的顺序放入程序中:

   调用 OPEN_CONNECTION

   调用 HELO

   调用 MAIL

   调用 RCPT for each recipient

   格式化电子邮件的内容然后调用MAIL

   调用 QUIT

  EmailUtils包规范

   EmailUtils包包括下列API:

   SetSender/GetSender-设置/取得发送者

   SetRecipient/GetRecipient -设置/取得接受者

   SetCcrecipient/GetCcrecipient -设置/取得抄件接受者

   SetMailHost/GetMailHost -设置/取得邮件主机

   SetSubject/GetSubject -设置/取得主题

   Send-发送邮件

  代码1说明了EmailUtils包的规范:

create or replace package EmailUtils as

procedure SetSender(pSender in varchar2);
function GetSender
return varchar2;

procedure SetRecipient(pRecipient in varchar2);
function GetRecipient
return varchar2;

procedure SetCcRecipient(pCcRecipient in varchar2);
function GetCcRecipient
return varchar2;

procedure SetMailHost(pMailHost in varchar2);
function GetMailHost
return varchar2;

procedure SetSubject(pSubject in varchar2);
function GetSubject
return varchar2;


procedure Send(pMessage in varchar2);

procedure Send(pSender in varchar2,
pRecipient in varchar2,
pMailHost in varchar2,
pCcRecipient in varchar2 := null,
pSubject in varchar2 := null,
pMessage in varchar2 := null);

end EmailUtils;
/

  可以看出,Send过程是重载过程:包规范中包括这个过程的两个版本。 一个版本当至少三个强制性参数要规定的时候引用,pSender,pRecipient和pMailHost:

procedure Send(pSender in varchar2,
pRecipient in varchar2,
pMailHost in varchar2,
pCcRecipient in varchar2 := null,
pSubject in varchar2 := null,
pMessage in varchar2 := null);

     另一个版本只有当提供pMessage参数值时执行:

   procedure Send(pMessage in varchar2);

  第二个版本是用作调试的版本。 所有的电子邮件消息共用同样的发送者、接受者、邮件主机、抄送接受者和主题信息,这些都是我在会话的开始的时候设置好的。 下面是一个PL/SQL程序块的例子:

begin

EmailUtils.SetSender('[email protected]');
EmailUtils.SetRecipient('[email protected]');
EmailUtils.SetCcRecipient('[email protected]');
EmailUtils.SetMailHost('MyServer.MyCompany.com');
EmailUtils.SetSubject('DeleteClassifications procedure: Run 1');

end;
/

  一个实际的电子邮件消息将在每个Send过程调用中被指定。 我们可以把所用的EmailUtils.Send()调用插入到我们调试的代码中,我们以前为了得到同样的调试结果使用的是DBMS_OUTPUT.PUT_LINE()调用。:

vMessage := 'Point 1.' || utl_tcp.crlf ||
'Rows processed: ' || to_char(vRows) || utl_tcp.crlf ||
'Elapsed time: ' || vTime;

EmailUtils.Send(vMessage);


vMessage := 'Point 3.' || utl_tcp.crlf ||
'Rows processed: ' || to_char(vRows) || utl_tcp.crlf ||
'Elapsed time: ' || vTime;

EmailUtils.Send(vMessage);

  代码2显示带有重载Send过程的EmailUtils规格。 我们可以看到,Send过程的代码相当简单。 UTL_SMTP包不提供用于格式化消息内容的应用编程接口。 而是由用户负责格式化消息。 这就是为什么下列程序块要被包含到每个Send过程中以便格式化电子邮件的头部。

vMessage := 'Date: ' ||
to_char(sysdate, 'fmDy, DD Mon YYYY fxHH24:MI:SS') ||
utl_tcp.crlf ||
'From: ' || pSender || utl_tcp.crlf ||
'Subject: ' || pSubject || utl_tcp.crlf ||
'To: ' || pRecipient || utl_tcp.crlf;

  同时,如果消息长度超过2000字符的话,你可能得到一个错误( ORA - 06502 : PL/SQL : numeric or value error)。 所以为了避免出现这个错误,我们使用下面的程序块,不允许消息超过2000个字符:

if length(vMessage) > 2000
then
vMessage := substr(vMessage, 1, 2000);
end if;

  如果需要发送带有超过2000字的电子邮件,那么可以使用另三个UTL_SMTP应用程序编程接口,提供比DATA()过程更加精细的控制。 首先, OPEN_DATA()发送数据命令。 然后WRITE_DATA()添加数据到你要发送的字符串中。 你可以调用WRITE_DATA()任意多次,这样你就可以一次写2000个字符以克服字数的限制。 最后, CLOSE_DATA()通过发送一个封装在CRLF中的终止周期结束电子邮件消息。

  实时消息使你的生活更加舒适

  从数据库发送电子邮件就是那么容易。 一旦你试用这个简单的操作,我相信你会发现它很有用,便于你的数据库操作,例如调试、远程的数据库监控和输出数据库数据。

  每个数据库开发者都有在代码中使用大量的DBMS_OUTPUT调用的调试经历。 在开始一个SQL * Plus会话之后,输入SET SERVEROUTPUT ON然后运行这个过程。 放进DBMS_OUTPUT.PUT_LINE调用的消息显示在屏幕上--但是只有在过程完成以后才能显示出来。 这个过程极端地麻烦,尤其在调试长的批处理时通常是要运行整晚。 你可以等待10到12小时仅仅是为了查出错误的代码,然后修改,再去等待下一个10到12个小时? 然而,如果你有访问消息的实时的办法,那么你可以在头5到10分钟内捕捉到问题。

  DBMS_OUTPUT包也有其他的缺点。 例如,它不接受可变的布尔类型以及它有255字符每行的限制(如果你想输出一个长的消息的话,那么你会得到这个异常:ORA - 20000 : ORU - 10028 : line length overflow, limit of 255 bytes per line)。 把它的缺点全部列出这已经超出本文的范围了,但是重要结论就是DBMS_OUTPUT包不许数据库开发者实时的看到消息。

  谈到服务器上的OS文件,你会不会喜欢把选定的数据从服务器中输出到一个Excel电子表格呢? 一个办法就是使用Oracle的UTL_FILE包,它提供了一个标准OS流文档输入/输出的限制级版本。 然而, PL/SQL程序只能访问在初始化文件INIT.ORA的UTL_FILE_DIR参数规定的目录。 这个参数大多数情况下是空的。为了使这个目录可用来进行文件访问,必须请数据库管理者修改初始化文件。 这有些麻烦。使用EmailUtils包,你可以简简单单的把数据写入一个电子邮件中,发送给自己,然后收到它的副本粘贴到自己喜欢的文档编辑器中。




相关文章

相关软件