昨天遇到比较“奇怪”的错误,job自动运行报错,但是手工执行不会出错。而且手工执行job运行的存储过程也不会出错。
仔细研究后发现问题是job和database link的特性的共同作用造成的。
我通过下面的例子来模仿错误,并加以说明。
SQL> conn yangtk/yangtk@test
已连接。
SQL> select * from user_db_links;
未选定行
SQL> select * from dba_db_links;
OWNER DB_LINK USERNAME HOST CREATED
--------- ----------------------- ---------- ---------- ---------
PUBLIC REP.YANGTINGKUN rep 21-10月-04
在当前用户下我没有建立数据库链,但是建有一个到rep.yangtingkun的公用数据库链。
在当前用户下执行select * from tab@rep.yangtingkun会找到并使用这个公用数据库链。
注意一点,这个数据库链的USERNAME是空,也就是说,在建立数据库链的时候没有指定CONNECT TO语句,建立这个数据库链的语句如下:
CREATE PUBLIC DATABASE LINK REP.YANGTINGKUN USING 'REP';
如果没有给出CONNECT TO语句,则调用数据库链的时候,会用当前session的用户名、密码去访问远端数据库。使用这种数据库链要求本地数据库和远端数据库具有相同的用户名和密码,否则将无法访问。
SQL> create or replace procedure p_test as
2 begin
3 for c in (select * from tab@rep.yangtingkun) loop
4 null;
5 end loop;
6 end;
7 /
过程已创建。
SQL> exec p_test;
PL/SQL 过程已成功完成。
接着建立存储过程,通过数据库链访问远端数据。
存储过程在本地执行成功。
SQL> declare
2 v_job number;
3 begin
4 dbms_job.submit(v_job, 'p_test;', sysdate, 'sysdate + 1/1440');
5 commit;
6 end;
7 /
PL/SQL 过程已成功完成。
SQL> select job, what, next_date, interval, failures, broken from user_jobs;
JOB WHAT NEXT_DATE INTERVAL FAILURES B
---------- ------------- ---------- ----------------- ---------- -
6 p_test; 01-12月-04 sysdate + 1/1440 0 N
将存储过程加入job中。
SQL> select job, failures, broken from user_jobs;
JOB FAILURES B
---------- ---------- -
6 8 N
经过一段时间检查job,发现已经出现了8次错误。
SQL> exec dbms_job.run(6);
PL/SQL 过程已成功完成。
SQL> select job, failures, broken from user_jobs;
JOB FAILURES B
---------- ---------- -
6 0 N
手工执行job,没有报错。
等待一段时间后,再次查看。发现job已经停止。
SQL> select job, failures, broken from user_jobs;
JOB FAILURES B
---------- ---------- -
6 16 Y
这时检查alert_test.log可以发现下面的错误:
Wed Dec 01 19:16:51 2004
Errors in file e:oracleadmintestudumptest_j000_7236.trc:
ORA-12012: 自动执行作业 6 出错
ORA-01005: null password given; logon denied
ORA-06512: 在"YANGTK.P_TEST", line 3
ORA-06512: 在line 1
根据上面这些信息,可以判断,job在自动执行的时候,虽然是以当前用户执行,但是并不包含当前用户的密码信息。
而手工执行job,由于运行在当前用户的session中,带有当前用户的用户名和密码信息,所以不会报错。
如果比较清晰的了解ORACLE数据库链和JOB的运行特点,就会发现,这个“奇怪”的错误并不奇怪。