今天一个开发同事私信我,说是在创建存储过程中提示😱ORA-00942: 表或视图不存在!!但是将存储过程中的sql拿出来单独执行时,sql语句能正常执行。其实到这里就能想到,单独的sql可以执行表明语句本身是正确,而存储过程中无法执行,应该是权限出了问题。通过查看该用户角色与权限,发现该用户拥有dba角色,但是在对象权限中没有访问该表的权限,在执行grant select on tablename to username后,创建存储过程正常。
  很多人会疑惑为什么出现这种情况呢?用户都拥有了DBA角色了,单独的sql也能执行,存储过程为什么不可以?下面我将通过实验过程来解释这其中的原因👇

1. 创建测试表

[oracle@jwdb:/home/oracle]$ sqlplus / as sysdba
create tablespace eason datafile '/oradata/orcl/eason.dbf' size 10m autoextend on;
create user hyj identified by hyj default tablespace eason ;
grant connect,resource to hyj;

create user fym identified by fym default tablespace eason ;
grant dba to fym;


[oracle@jwdb:/home/oracle]$ sqlplus hyj/hyj
create table students(
id int,
name varchar(20)
);

hyj@ORCL> INSERT ALL INTO students values(3,'张三')
INTO students values (4,'李四')
INTO students values (5,'王五')
INTO students values (6,'赵六')
INTO students values (7,'孙七')
select 1 from dual;    

5 rows created.

Elapsed: 00:00:00.09
hyj@ORCL> select * from students;

	ID NAME
----- -----------
	 3 张三
	 4 李四
	 5 王五
	 6 赵六
	 7 孙七

2.创建存储过程

  • 确认用户的角色和权限
system@ORCL> select grantee,granted_role,default_role,admin_option from dba_role_privs  where grantee ='FYM';

GRANTEE 		       GRANTED_ROLE		      DEF ADM
------------------------------ ------------------------------ --- ---
FYM			       DBA			      YES NO
#fym用户拥有的对象权限
sysem@ORCL> select privilege,table_name,grantee from dba_tab_privs where grantee='FYM';

no rows selected

Elapsed: 00:00:00.07
  • 创建PROCEDURE
fym@ORCL> CREATE OR REPLACE PROCEDURE TEST_update01
      as v_sql varchar2(2000) := '';
       BEGIN
             v_sql := 'update hyj.students set id=id+1';
             EXECUTE IMMEDIATE v_sql;
       END ;
  /
  2    3    4    5    6    7  
Procedure created.
fym@ORCL> 
 BEGIN
     TEST_UPDATE01;
 END;
 /fym@ORCL>   2    3    4  
 BEGIN
*
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at "FYM.TEST_UPDATE01", line 5
ORA-06512: at line 2

  • 单独执行存储过程中的sql
fym@ORCL> update hyj.students set id=id+1;

5 rows updated.

Elapsed: 00:00:00.00
fym@ORCL> select * from hyj.students;

	ID NAME
---------- ------------------------------------------
	 4 张三
	 5 李四
	 6 王五
	 7 赵六
	 8 孙七

💥可以看到这里将procedure中的sql部分单独取出执行,可以再fym用户下正常执行,在procedure中缺报错❌ORA-00942: table or view does not exist❌
✏️下面我们在创建一个存储过程,观察一下有什么不同之处

3.创建存储过程(调用者权限)

fym@ORCL> CREATE OR REPLACE PROCEDURE TEST_update02 AUTHID CURRENT_USER 
      as v_sql varchar2(2000) := '';
       BEGIN
             v_sql := 'update hyj.students set id=id+1';
             EXECUTE IMMEDIATE v_sql;
       END ;
  /
  2    3    4    5    6    7  
Procedure created.

Elapsed: 00:00:00.12

fym@ORCL>  BEGIN
     TEST_UPDATE02;
 END;
 /  2    3    4  

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.01

fym@ORCL> select * from hyj.students;

	ID NAME
---------- --------------------------------------------------------------------------------
	 5 张三
	 6 李四
	 7 王五
	 8 赵六
	 9 孙七

⁉️为什么同样内容的存储过程,FYM用户现在就能执行成功了呢?
🚩这里我们创建存储过程时,使用了AUTHID CURRENT_USER模式

Oracle 从8i开始引入了调用者权限体系结构,之前一直使用定义者权限体系结构(默认情况下是定义者权限)。下面描述了调用者权限与定义者权限之间的差异

1 执行的schema不同,操作的对象也不同
在定义者(definer)权限下,执行的用户操作的schema为定义者,所操作的对象是定义者在编译时指定的对象。
在调用者(invoker)权限下,执行的用户操作的schema为当前用户,所操作的对象是当前模式下的对象。

2、执行的权限不同
在定义者(definer)权限下,当前用户的权限为角色无效情况下所拥有的权限。
在调用者(invoker)权限下,当前用户的权限为当前所拥有的权限(含角色)。
3、执行的效率不同
在定义者(definer)权限下,过程被静态编译静态执行(相对而言),所执行sql语句在共享区池中是可被共享使用的
在调用者(invoker)权限下,过程静态编译,但动态执行,虽然执行的语句相同,但不同用户执行,其sql语句在共享池中并不能共享

✅ 知道了原理,我们就知道如何解决问题啦

sys@ORCL> grant update on hyj.students to fym;
Grant succeeded.
Elapsed: 00:00:00.02

fym@ORCL> BEGIN
     TEST_UPDATE01;
 END;
 /  2    3    4  
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.01

fym@ORCL 01:13:08> select * from hyj.students;

	ID NAME
---------- --------------------------------------------------------------------------------
	 6 张三
	 7 李四
	 8 王五
	 9 赵六
	10 孙七

🎯现在创建的存储过程(默认定义者模式)可以正常执行

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐