Oracle没有对JOB设置相应的权限,任何用户都可以使用DBMS_JOB包建立自己的JOB。也正是因为没有权限的限制,所以使用DBMS_JOB包无法删除其他用户下的JOB。
因此一直认为Oracle无法删除其他用户下的JOB,最多只能在删除用户的时候级联删除。看了论坛中jametong的回复,感觉Oracle中真的很少有什么东西不能做,而主要是你是否知道或能否想到的。受jametong的启发,又总结出一种删除其他用户下JOB的方法。
下面总结了这两种方法,一个是通过Undocument的包DBMS_IJOB,这种情况下需要DBMS_IJOB的执行权限。另一种方法需要CREATE ANY PROCEDURE和EXECUTE ANY PROCEDURE的权限。
SQL> conn yangtk/yangtk@test4
已连接。
SQL> select job, priv_user, what from user_jobs;
未选定行
SQL> declare
2 v_job number;
3 begin
4 dbms_job.submit(v_job, 'null;', sysdate, 'sysdate + 1');
5 commit;
6 end;
7 /
PL/SQL 过程已成功完成。
SQL> select job, priv_user, what from user_jobs;
JOB PRIV_USER WHAT
---------- ------------------------------ ---------------------
84 YANGTK null;
SQL> conn /@test4 as sysdba
已连接。
SQL> select job, priv_user, what from dba_jobs;
JOB PRIV_USER WHAT
---------- ------------------------------ ----------------------
84 YANGTK null;
SQL> exec dbms_job.remove(84);
BEGIN dbms_job.remove(84); END;
*
ERROR 位于第 1 行:
ORA-23421: 作业编号84在作业队列中不是一个作业
ORA-06512: 在"SYS.DBMS_SYS_ERROR", line 86
ORA-06512: 在"SYS.DBMS_IJOB", line 529
ORA-06512: 在"SYS.DBMS_JOB", line 171
ORA-06512: 在line 1
即使是SYS用户也无法通过DBMS_JOB包删除其他用户下的JOB。但是可以通过其他两种方法来实现。
方法一:通过DBMS_IJOB包。
SQL> create user a identified by a;
用户已创建
SQL> grant create session to a;
授权成功。
SQL> grant execute on dbms_ijob to a;
授权成功。
SQL> conn a/a@test4
已连接。
SQL> select job, priv_user, what from all_jobs;
未选定行
SQL> exec dbms_job.remove(84);
BEGIN dbms_job.remove(84); END;
*
ERROR 位于第 1 行:
ORA-23421: 作业编号84在作业队列中不是一个作业
ORA-06512: 在"SYS.DBMS_SYS_ERROR", line 86
ORA-06512: 在"SYS.DBMS_IJOB", line 529
ORA-06512: 在"SYS.DBMS_JOB", line 171
ORA-06512: 在line 1
SQL> exec sys.dbms_ijob.remove(84);
PL/SQL 过程已成功完成。
SQL> commit;
提交完成。
SQL> conn yangtk/yangtk@test4
已连接。
SQL> select job, priv_user, what from user_jobs;
未选定行
方法二:通过建立其他用户下的存储过程来执行dbms_job包。
SQL> show user
USER 为"YANGTK"
SQL> declare
2 v_job number;
3 begin
4 dbms_job.submit(v_job, 'null;', sysdate, 'sysdate + 1');
5 commit;
6 end;
7 /
PL/SQL 过程已成功完成。
SQL> select job, priv_user, what from user_jobs;
JOB PRIV_USER WHAT
---------- ------------------------------ --------------------
85 YANGTK null;
SQL> conn /@test4 as sysdba
已连接。
SQL> grant create session to b identified by b;
授权成功。
SQL> grant create any procedure, execute any procedure to b;
授权成功。
SQL> conn b/b@test4
已连接。
SQL> create procedure yangtk.p_execute(p_str in varchar2) as
2 begin
3 execute immediate p_str;
4 end;
5 /
过程已创建。
注意,如果需要以CREATE OR REPLACE方式创建存储过程,还需要ALTER ANY PROCEDURE权限。
SQL> begin
2 yangtk.p_execute('begin dbms_job.remove(85); commit; end;');
3 end;
4 /
PL/SQL 过程已成功完成。
SQL> conn yangtk/yangtk@test4
已连接。
SQL> select job, priv_user, what from user_jobs;
未选定行
第二种方法还支持删除其他用户下数据库链的功能。
SQL> create database link yangtk.yangtingkun;
数据库链接已创建。
SQL> conn /@test4 as sysdba
已连接。
SQL> col db_link format a40
SQL> select owner, db_link from dba_db_links where owner = 'YANGTK';
OWNER DB_LINK
------------------------------ ---------------------------
YANGTK YANGTK.YANGTINGKUN
SQL> drop database link yangtk.yangtingkun;
drop database link yangtk.yangtingkun
*
ERROR 位于第 1 行:
ORA-02024: 未找到数据库链接
SQL> drop database link yangtk.yangtk.yangtingkun;
drop database link yangtk.yangtk.yangtingkun
*
ERROR 位于第 1 行:
ORA-02024: 未找到数据库链接
SQL> conn b/b@test4
已连接。
SQL> exec yangtk.p_execute('drop database link yangtk.yangtingkun')
PL/SQL 过程已成功完成。
SQL> conn yangtk/yangtk@test4
已连接。
SQL> select * from user_db_links;
未选定行
需要注意的是,DBMS_IJOB包允许建立、删除、修改任意用户的JOB,这个权限很大,应当慎重授权。而第二种方法需要的CREATE ANY PROCEDURE和EXECUTE ANY PROCEDURE更要小心,不应该授权给除DBA以外的其他用户。