2、使用db_admin用户登录数据库,创建如下存储过程;

create or replace procedure compile_invalid_views(

p_owner varchar2

--编译某个用户下的无效视图

str_sql varchar2(2000);

begin

for invalid_views in (select object_name from all_OBJECTS

where status = 'INVALID' and object_type = 'VIEW' and owner=upper(p_owner))

alter_sql := 'alter view '||p_owner||'.' ||invalid_views.object_name || ' compile';

begin

execute immediate alter_sql;

end loop;

3、指定定时任务,定期调用存储过程来从新编译sysadm用户下的无效视图;

*/5 * * * * sh /home/oracle2/scripts/compile_invalid_views.sh

[oracle2@B-GH4-PSDB-01 ~]$ cat /home/oracle2/scripts/compile_invalid_views.sh

#!/bin/bash

source /home/oracle2/.bash_profile

sql_str=sqlplus -S db_admin/'passwd'@mz <

echo $sql_str

[oracle2@B-GH4-PSDB-01 ~]$

然后过了几天后,发现有的无效视图并没有被从新编译,业务还是报错,太奇怪了,db_admin有dba权限,执行存储过程没有报错;

二、原因分析:

存储过程分成两种权限:

1.定义者权限 AUTHID DEFINER

2.调用者权限 AUTHID CURRENT_USER

默认的情况下使用的是定义者权限,也就是存储过程内部的权限是继承的创建者的权限;

1、定义者权限使用遇到的问题:

当使用定义者权限时候,不管是你自己去call,还是其他用户去call,效果是一样的,都是用你的权限去执行。但是,不是你的全部权限,是把所有Roles的权限去掉了( 因为我只给db_admin授权了dba的权限,但是他是个角色,所以存储过程里面会去掉dba这个角色,这是问题的关键,一般不注意 ),当去掉dba角色后,再查询all_OBJECTS是不能查到别的schema下视图信息的,所以也就无法从新编译别的用户下的视图了。

2、调用者权限使用遇到的问题:

当使用调用者权限时候,用什么用户去call存储过程,就用谁的权限,而且包括角色权限。请注意,用数据字典

user_xxx, 这个是调用者的,所以建议不要用他,而用all_xxx或dba_xxxx. (当然是要求调用者有select_catalog_role)

另外,涉及到create table, create index, ...要确认调用者是否具备在该存储过程所在的schema下有此权限(如果调用者就是你自己,肯定没问题)。

三、解决问题:

方法1 :这样的话需要保证调用者的权限是足够的,调用者只有执行存储过程的权限是不行的!因为调用者是dba权限,所以如下这样让存储过程继承调用者的权限,是可以解决问题的!

添加AUTHID CURRENT_USER 关键字,这样存储过程就继承执行者(调用者)的所有权限,包括角色权限!

create or replace procedure compile_invalid_views(

p_owner varchar2

) AUTHID CURRENT_USER as

--编译某个用户下的无效视图

str_sql varchar2(2000);

begin

for invalid_views in (select object_name from all_OBJECTS

where status = 'INVALID' and object_type = 'VIEW' and owner=upper(p_owner))

alter_sql := 'alter view '||p_owner||'.' ||invalid_views.object_name || ' compile';

begin

execute immediate alter_sql;

end loop;

方法2 :建议这种的方式,存储过程保持默认继承定义者权限,依旧使用db_admin用户创建存储过程!

如果db_admin只有dba权限,存储过程继承定义者权限的时候,会去掉其拥有的角色的权限,所以会去掉dba权限;所以需要给db_admin用户dba之外的权限,不会去掉的权限,如下所示:

SQL> grant alter any table to db_admin; 因为需要存储过程需要执行alter view,

Grant succeeded.

SQL> grant select any table to db_admin; #因为需要能查看别的用户下的view后,才能在all_objects中查看到别的用户的视图信息!

SQL> grant connect to db_admin; #因为后面需要收回dba,所以需要加connect权限

最后还可以回收dba权限;并且由于存储过程是自己账户下面的,自己的账号是可以执行的

SQL>revoke dba from db_admin;

方法3 :这种方式不完美,因为只能从新编译sysadm用户的试图,当你传别的schema的时候,还是有问题!

在sysadm下创建对应的存储过程,这样继承了sysadm这个用户的权限,存储过程中也是可以查到自己的下面的试图的,所以问题就解决了,但是一旦别的用户下的试图有问题也是不能从新编译的!

create or replace procedure sysadm.compile_invalid_views(

p_owner varchar2

--编译某个用户下的无效视图

str_sql varchar2(2000);

begin

for invalid_views in (select object_name from all_OBJECTS

where status = 'INVALID' and object_type = 'VIEW' and owner=upper(p_owner))

alter_sql := 'alter view '||p_owner||'.' ||invalid_views.object_name || ' compile';

begin

execute immediate alter_sql;

end loop;

然后使用db_admin用户去调用这个存储过程!

exec sysadm.compile_invalid_views('sysadm');

综上所述 :Oracle创建存储过程的时候,存储过程默认继承的是定义者,也就是创建者的权限,但是会去掉定义者拥有的 角色 ,这个需要大家注意!

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/29654823/viewspace-2933963/,如需转载,请注明出处,否则将追究法律责任。

广播电视节目制作经营许可证(京) 字第1234号 中国互联网协会会员