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 对象依赖循环的主要内容,如果未能解决你的问题,请参考以下文章

Spring是如何解决循环依赖的?

彻底理解Spring如何解决循环依赖

spring-循环依赖

Spring的循环依赖原理解析

Spring中的循环依赖及解决

Spring循环依赖原理分析