在Oracle数据库的日常运维中,很多场景需要通过定时任务发送邮件来传递告警、业务通知等信息,不少用户会选择创建发邮件job来实现这个需求,但配置不当很容易引发各类故障,影响数据库正常运行。

常见故障表现
创建Oracle发邮件job后可能出现的故障主要有以下几类:
- job执行失败,查看作业日志显示发送邮件相关步骤报错
- job长时间运行不结束,占用数据库会话资源,导致其他业务请求响应变慢
- 邮件发送频率异常,出现重复发送或者完全不发的情况
- 数据库alert日志出现大量和邮件发送相关的错误记录,甚至引发数据库挂起
故障排查步骤
1. 查看job执行日志
首先可以通过数据字典视图查询对应job的执行情况,确认job是否正常运行、报错信息是什么。常用的查询语句如下:
-- 查询所有job的基本信息和最近执行情况 SELECT job, last_date, last_sec, next_date, next_sec, broken, failures, what FROM dba_jobs; -- 查询指定job的执行日志,假设job编号为123 SELECT * FROM dba_scheduler_job_log WHERE job_name = 'JOB_SEND_MAIL';
2. 检查发邮件存储过程配置
发邮件job通常会调用自定义的存储过程,需要检查存储过程中邮件服务器的配置是否正确,比如SMTP服务器地址、端口、发件人账号密码等参数是否有误。同时要注意Oracle数据库访问外部网络的相关权限是否开启,很多故障是因为数据库没有权限访问SMTP服务器导致的。
3. 校验job调度参数
检查job的调度频率、执行时间等参数是否合理,避免设置过于频繁的调度导致资源占用过高。如果job的what字段中调用的存储过程存在死循环或者未处理的异常,也会导致job执行卡住引发故障。
4. 查看数据库告警日志
如果job执行引发了数据库层面的错误,需要查看$ORACLE_BASE/diag/rdbms/实例名/实例名/trace目录下的alert日志,定位更底层的错误原因。
规范发邮件job创建示例
以下是一个完整的、可正常执行的发邮件job创建示例,包含发邮件存储过程和job创建两部分:
发邮件存储过程
CREATE OR REPLACE PROCEDURE send_mail_proc(
p_recipient IN VARCHAR2, -- 收件人邮箱
p_subject IN VARCHAR2, -- 邮件主题
p_body IN VARCHAR2 -- 邮件正文
) AS
v_mail_conn UTL_SMTP.CONNECTION;
v_host VARCHAR2(100) := 'mail.ipipp.com'; -- SMTP服务器地址,替换成实际地址
v_port NUMBER := 25; -- SMTP端口
v_user VARCHAR2(100) := 'sender@ipipp.com';-- 发件人账号
v_pass VARCHAR2(100) := 'password123'; -- 发件人密码
v_sender VARCHAR2(100) := 'sender@ipipp.com';
BEGIN
-- 建立SMTP连接
v_mail_conn := UTL_SMTP.OPEN_CONNECTION(v_host, v_port);
-- 握手
UTL_SMTP.HELO(v_mail_conn, v_host);
-- 登录认证
UTL_SMTP.COMMAND(v_mail_conn, 'AUTH LOGIN');
UTL_SMTP.COMMAND(v_mail_conn, UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(v_user))));
UTL_SMTP.COMMAND(v_mail_conn, UTL_RAW.CAST_TO_VARCHAR2(UTL_ENCODE.BASE64_ENCODE(UTL_RAW.CAST_TO_RAW(v_pass))));
-- 设置发件人
UTL_SMTP.MAIL(v_mail_conn, v_sender);
-- 设置收件人
UTL_SMTP.RCPT(v_mail_conn, p_recipient);
-- 设置邮件内容
UTL_SMTP.OPEN_DATA(v_mail_conn);
UTL_SMTP.WRITE_DATA(v_mail_conn, 'From: ' || v_sender || UTL_TCP.CRLF);
UTL_SMTP.WRITE_DATA(v_mail_conn, 'To: ' || p_recipient || UTL_TCP.CRLF);
UTL_SMTP.WRITE_DATA(v_mail_conn, 'Subject: ' || p_subject || UTL_TCP.CRLF);
UTL_SMTP.WRITE_DATA(v_mail_conn, UTL_TCP.CRLF || p_body);
UTL_SMTP.CLOSE_DATA(v_mail_conn);
-- 关闭连接
UTL_SMTP.QUIT(v_mail_conn);
EXCEPTION
WHEN OTHERS THEN
-- 出现异常时关闭连接,避免资源泄露
IF UTL_SMTP.IS_OPEN(v_mail_conn) THEN
UTL_SMTP.QUIT(v_mail_conn);
END IF;
RAISE;
END send_mail_proc;
创建发邮件job
BEGIN
DBMS_SCHEDULER.CREATE_JOB(
job_name => 'JOB_SEND_MAIL',
job_type => 'STORED_PROCEDURE',
job_action => 'send_mail_proc',
number_of_arguments => 3,
start_date => SYSTIMESTAMP,
repeat_interval => 'FREQ=DAILY; BYHOUR=9; BYMINUTE=0', -- 每天9点执行
enabled => FALSE,
auto_drop => FALSE,
comments => '每日发送业务通知邮件'
);
-- 设置job参数
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
job_name => 'JOB_SEND_MAIL',
argument_position => 1,
argument_value => 'receiver@ipipp.com'
);
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
job_name => 'JOB_SEND_MAIL',
argument_position => 2,
argument_value => '每日业务通知'
);
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
job_name => 'JOB_SEND_MAIL',
argument_position => 3,
argument_value => '今日业务运行正常,无异常告警'
);
-- 启用job
DBMS_SCHEDULER.ENABLE('JOB_SEND_MAIL');
END;
/
故障预防建议
为了避免创建Oracle发邮件job引发故障,建议遵循以下规范:
- 发邮件存储过程必须添加完整的异常处理逻辑,避免异常导致job卡住
- 测试阶段先手动调用存储过程验证邮件发送功能正常,再创建job
- job的调度频率不要设置过高,避免频繁占用数据库和外部服务器资源
- 定期检查job的执行日志,及时发现执行异常并处理
- 如果SMTP服务器需要更换,及时同步更新存储过程中的相关配置参数
Oracle_job发邮件故障排查PLSQL修改时间:2026-07-14 13:57:34