处理数据库中的PL/SQL代码库应当遵循一定的规则和组织方法。从Oracle 8i到Oracle 10g的数据库都为组织代码库提供了两种选择,分别是定义者权限模式和调用者权限模式。本章将要探讨的是实现调用者权限模式的方法。
在默认情况下,Oracle一直是使用定义者权限体系结构的,但其实早在Oracle 8i中就已经介绍了调用者权限体系结构。许多的ERP/CRM数据库应用程序都使用了调用者权限这个概念。当处理集中式数据时,使用定义者权限体系结构可以创建健壮的应用程序。
Oracle应用程序套件使用定义者权限体系来共享通用代码组件和管理内部组件接口。因为数据都分布在同一个Oracle应用程序实例的各个子系统中,所以Oracle应用程序使用一个授权和同义词的体系来实现定义者权限。
本章独立于本书的其他章节,因为本章的内容都只是当前Oracle数据库版本才开始支持的,它包含以下几个方面的内容:
● 介绍定义者权限和调用者权限的概念
● 定义者权限的概念
● 调用者权限的概念
● 理解权限体系
● 理解定义者权限体系结构
● 理解调用者权限体系结构
● 比较和对照两种体系结构的实现策略
使用权限体系的原因:
我们使用定义者权限或者调用者权限来执行Oracle数据库中的应用程序。定义者权限模式确保我们能控制对集中式数据的插入、更新和删除操作,而调用者权限模式则确保我们能控制对分布式数据的插入、更新和删除操作。
利用定义者或调用者体系结构创建的应用程序具有更好的可控性和组织结构,并且也更易于使用、支持和维护。如果我们没有理解两种体系结构的特性,只是接受默认的设置,那可能会导致我们犯一些关键性的错误,同时应用程序的复杂度以及支撑运行的成本也会增加。
本章的重点是介绍、比较与对照,以及演示在Oracle中实现定义者权限和调用者权限体系结构的方法。由于本书并不是使用PL/SQL程序体的基础教材,您应该自己研究一下第8章到第10章中的Oracle 10g程序实例,这些示例包含存储程序单元的所有特征—— 存储程序单元是一些独立的过程、函数、包和触发器。
这些概念的演示需要两种用户模式。在运行本章所有的示例之前应该运行create_invoker_user.sql脚本文件,这个文件负责创建、撤销以及重建MYAPP用户/模式和PLSQL用户/模式,但运行这个文件需要在SYSTEM用户/模式下或得到授权DBA的许可。
注意:
用户和模式是同义的,出于使用简单的考虑,我们在本章余下的部分中都使用模式这个词。
4.1 介绍定义者权限和调用者权限的概念
在定义存储PL/SQL程序单元时要选择使用定义者权限或调用者权限。在默认情况下,PL/SQL程序单元都是定义者权限程序。我们先来介绍一下定义者权限和调用者权限的基本概念。
4.1.1 定义者权限的概念
定义者权限PL/SQL程序单元是以这个程序单元拥有者的特权来执行它的,也就是说,任何具有这个PL/SQL程序单元执行权的用户都可以访问程序中的对象。所有具有执行权的用户都有相同的访问权限,当这些用户访问同一张数据表时就出现问题了,这是需要解决的。
使用定义者权限模式的原因:
当遇到下面两种情况之一时,我们使用定义者权限模式。一种情况是,我们对所有的外部模式都授予相同的执行特权,并且所有的数据都在一张单独的表中;另一种情况是,应用程序有一个基于连接和会话信息的安全系统。
Oracle的电子商务应用套件(Applications E-Business Suite)中部署了定义者权限,这是一个强大的体系结构,特别是在部署中包括了能够基于用户权限而改变的上下文视图时。我们推荐在联合式处理模型中使用定义者权限。
小提示:
关于连接和会话信息的安全系统使您只能以受限的或并行的方式,访问同一代码和数据库表的不同信息集。
在存储PL/SQL程序中使用定义者权限可以确保您能控制数据的插入、更新和删除操作。您可以像ERP/CRM应用程序那样通过创建应用程序或授权许可元数据和安全程序来做到这一点。许多ERP/CRM程序通过使用逐行数据库触发器来增强用户权限,但是这样做的代价是巨大的,因为它增加了完成事务的时间。触发器也是函数,它是基于用户级安全对应用层元数据集合的维护。
数据集中处理是一个折中的方法,这样可以避免多数据流之间数据的一致性问题。但同时带来的不利影响是数据量会显著增加,同时数据吞吐量可能会下降。
注意:
以定义者权限模式工作的Oracle应用程序,通过使用一组复杂的存储PL/SQL应用程序元数据集合和共享库,实现了APPS这种单一模式下的并行操作,同时对APPLSYSPUB和APPLSYS模式进行安全管理。
通过在PLSQL模式下使用下面的PL/SQL包,我们可以看到定义者权限开发的效用。执行SQL *Plus命令SHOW USER可以确认我们是在PLSQL模式下,然后我们应该运行create_definer1.sql脚本来创建这个包:
-- Available online as part of create_definer1.sql file.
-- Create a DEFINER_RIGHTS package.
CREATE OR REPLACE PACKAGE definer_rights IS
-- Define a GET_LITERAL function.
FUNCTION get_literal
( literal VARCHAR2 )
RETURN VARCHAR2;
END;
/
-- Create a DEFINER_RIGHTS package body.
CREATE OR REPLACE PACKAGE BODY definer_rights IS
-- Define a GET_LITERAL function.
FUNCTION get_literal
( literal VARCHAR2 )
RETURN VARCHAR2 IS
BEGIN
-- Use an implicit for-loop to avoid declaring variables.
FOR i IN (SELECT literal
FROM dual) LOOP
-- Return the value.
RETURN 'Called by ['||literal||']';
END LOOP;
END get_literal;
END definer_rights;
/
脚本创建的存储PL/SQL包具有下面几个特征:
● 在definer_rights包的包规范中定义get_literal函数;
● 创建包主体并实现get_literal函数,这个函数:
● 有且仅有一个VARCHAR2类型的形参literal;
● 用一个具有隐式游标的for循环从DUAL表中选择实参表示的那一列;
● 返回VARCHAR2类型的实参值。
创建包规范和包主体后,create_definer1.sql脚本给MYAPP模式授予EXECUTE权,如下所示:
-- Available online as part of create_definer1.sql file.
-- Grant EXECUTE privileges to MYAPP schema.
GRANT EXECUTE ON definer_rights TO myapp;
在PLSQL模式下使用下面的语句查询包的定义者:
SELECT definer_rights.get_literal(USER)
FROM dual;
输出如下:
DEFINER_RIGHTS.GET_LITERAL(USER)
--------------------------------------
Called by [PLSQL]
在验证本地的存储PL/SQL包工作在PLSQL模式后,使用下面的命令来连接MYAPP模式:
CONN MYAPP/MYAPP
使用SQL*Plus命令SHOW USER验证您处在正确的模式下,如下所示:
USER is "MYAPP"
我们可以通过运行一个与在所有者模式下运行的查询相类似的查询,来测试具有定义者权限的包。在存储包、函数或过程名之前,我们需要链接到一个用户模式。当我们将一个用户链接到包上的同时,也将用户模式链接到包中定义的函数或过程上了。
注意:
链接是将模式连接到程序体和对象的过程。链接时需要指明模式名和周期。
我们应该在当前点检查用户模式,假如处于MYAPP模式,使用SQL*Plus命令SHOW USER进行检查,然后运行下面的查询:
SELECT plsql.definer_rights.get_literal(USER)
FROM dual;
输出如下所示:
PLSQL.DEFINER_RIGHTS.GET_LITERAL(USER)
--------------------------------------
Called by [MYAPP]
现在我们已经用另一个模式存储的PL/SQL包的执行权限查询了公有DUAL表。create_definer2.sql脚本稍微地改变了这个问题,现在以包定义者的角色创建和使用这个包。您应该以PLSQL用户的身份重新连接,并使用SQL*Plus来验证您就是PLSQL用户。然后,在PLSQL模式下运行create_definer2.sql脚本来定义local_table,如下所示:
-- Available online as part of create_definer2.sql file.
-- Create a local table.
CREATE TABLE local_table
( owner_name VARCHAR2(30 CHAR)
, user_name VARCHAR2(30 CHAR) );
接下来,修改包definer_rights,如下所示:
-- This is found in the create_definer2.sql file.
-- Create a DEFINER_RIGHTS package.
CREATE OR REPLACE PACKAGE definer_rights IS
-- Define a SET_DATA function.
FUNCTION set_data
( user_in VARCHAR2 )
RETURN BOOLEAN;
-- Define a GET_DATA function.
FUNCTION get_data
( user_in VARCHAR2 )
RETURN VARCHAR2;
END;
/
-- Create a DEFINER_RIGHTS package body.
CREATE OR REPLACE PACKAGE BODY definer_rights IS
-- Define a SET_DATA function.
FUNCTION set_data
( user_in VARCHAR2 )
RETURN BOOLEAN IS
-- Define default return value.
retval BOOLEAN := FALSE;
BEGIN
-- Use an implicit for-loop to avoid declaring variables.
INSERT
INTO local_table
VALUES
('PLSQL'
, user_in );
COMMIT;
-- Reset return value.
retval := TRUE;
-- Return value.
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/523774/viewspace-374307/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/523774/viewspace-374307/