Oracle 对象依赖循环
Posted
技术标签:
【中文标题】Oracle 对象依赖循环【英文标题】:Oracle object dependency loop 【发布时间】:2013-09-05 08:08:39 【问题描述】:当我尝试在 Oracle 数据库中编译我的项目时遇到问题。为了更简单,我有三个对象:2 个包(UTILS 和 TYPES)和 1 个视图(VIEW)。
包 UTILS 使用包 TYPES 中定义的类型。 Package TYPES 使用 VIEW 作为其中一种类型的基础。并且 VIEW 在其脚本中使用包 UTILS 中的函数。当我尝试对这些对象之一进行一些更改时,我无法编译,因为一切都处于无效状态。所以创建了某种对象依赖循环。
请帮我解决这个问题。
例如,有没有编译下面的代码?每个对象在语法上都是正确的,但是如何将它们全部编译在一起呢?
create or replace package my_types is
type type1 is table of number;
type type2 is table of my_view%rowtype;
end;
/
create or replace package my_utils is
function get_1 return number;
procedure do_something(parameter my_types.type2);
end;
/
create or replace package body my_utils is
function get_1 return number is
begin
return 1;
end;
procedure do_something(parameter my_types.type2) is
begin
null;
end;
end;
/
create or replace force view my_view as
select * from dual
where 1 = my_utils.get_1();
exec dbms_utility.compile_schema(user, false);
select object_name from user_objects where status <> 'VALID';
【问题讨论】:
打破循环?使函数的执行成为运行时效果(而不是嵌入到查询中)——例如:从字符串中执行函数。 所以打破循环是解决这个问题的唯一方法吗?我认为在编译包/视图以忽略其依赖项的无效状态时可能会有一些提示。 不知道——你会想要一些 oracle 无所不知的 :-) 我对 Postgres 比较熟悉,这就是我在那里的做法。 (它不会受到 exact 问题的影响,但您仍然可以创建依赖循环)。 唯一明智的方法是打破循环,正如@David-SkyMesh 所建议的那样。请您将代码添加到您的问题中吗? @jonearles - 我相信你已经看过这个,但是UTL_RECOMP
无法直接或通过utlrp
解决它,这很有趣。建议在我认为的这个版本中它是不可解决的,无论如何都不需要拆分。
【参考方案1】:
如果你在两个视图中打破视图,你可以打破循环依赖:
create or replace view my_view_1
as select * from dual;
create or replace package my_types is
type type1 is table of number;
type type2 is table of my_view_1%rowtype;
end;
/
create or replace package my_utils is
function get_1 return number;
procedure do_something(parameter my_types.type2);
end;
/
create or replace package body my_utils is
function get_1 return number is
begin
return 1;
end;
procedure do_something(parameter my_types.type2) is
begin
null;
end;
end;
/
create or replace view my_view as
select * from my_view_1
where 1 = my_utils.get_1();
编辑:另一种可能性是将包 my_utils 分成两部分:
create or replace package my_utils_1 is
function get_1 return number;
end;
/
create or replace package body my_utils_1 is
function get_1 return number is
begin
return 1;
end;
end;
/
create or replace view my_view as
select * from dual
where 1 = my_utils_1.get_1();
create or replace package my_types is
type type1 is table of number;
type type2 is table of my_view%rowtype;
end;
/
create or replace package my_utils_2 is
procedure do_something(parameter my_types.type2);
end;
/
create or replace package body my_utils_2 is
procedure do_something(parameter my_types.type2) is
begin
null;
end;
end;
/
【讨论】:
+1 这是一个可能的解决方案,但对于赏金,我正在寻找更好的解决方案。创建两个视图并不理想,因为它们需要保持同步。在更现实的场景中,如果不重复大量逻辑,视图就无法如此轻松地拆分。【参考方案2】:我会避免使用打包类型和 %ROWTYPE。这些不是标准 SQL,可以替换为Structured Types
create or replace view my_view_1
as select * from dual;
create or replace type type1 as table of number;
create or replace type type2 as object (DUMMY VARCHAR2(1 byte));
create or replace type table_type2 as table of type2;
create or replace package my_utils is
function get_1 return number;
procedure do_something(parameter table_type2);
end;
/
create or replace package body my_utils is
function get_1 return number is
begin
return 1;
end;
procedure do_something(parameter table_type2) is
begin
null;
end;
end;
/
create or replace view my_view as
select * from my_view_1
where 1 = my_utils.get_1();
【讨论】:
不确定标准 SQL 带来了什么。根据对象类型的使用(我们在这里没有看到),它可能会影响性能...... 打包类型和 %ROWTYPE 只能在 PL/SQL 中使用。您不能使用 SQL 查询或视图来选择它们。在性能方面,它们不会有太大不同【参考方案3】:如果您不想/不能拆分您的包或视图,您始终可以先创建视图的虚拟版本,编译包,然后创建“真实”视图:
create or replace package my_types is
type type1 is table of number;
type type2 is table of my_view%rowtype;
end;
/
create or replace package my_utils is
function get_1 return number;
procedure do_something(parameter my_types.type2);
end;
/
create or replace package body my_utils is
function get_1 return number is
begin
return 1;
end;
procedure do_something(parameter my_types.type2) is
begin
null;
end;
end;
/
create or replace force view my_view as
select * from dual;
exec dbms_utility.compile_schema(user, false);
create or replace force view my_view as
select * from dual
where 1 = my_utils.get_1();
select object_name from user_objects where status <> 'VALID';
【讨论】:
这不适用于 11.2.0.3.0。 dummy-version 技巧适用于简单的 2 向依赖,但在这种情况下似乎不起作用。 @jonearles 我在 11.1.0.6 上对其进行了测试,它运行良好。如果您在 11.2.0.3 上测试它 - 重新编译后所有对象都无效吗? 是的,它们都是无效的。它在 Express Edition 11.2.0.2 上也失败了,这里是 SQL Fiddle。也许这是 11.2 中的一个错误,但我在 Oracle 支持上找不到任何东西。 这种方法也适用于 10.2.0.5,所以这个问题在 11gR2 中肯定是新问题。以上是关于Oracle 对象依赖循环的主要内容,如果未能解决你的问题,请参考以下文章