在 Oracle DB 中如何避免反编译依赖于 DBLink 的对象?

In Oracle DB how to avoid decompiling of objects dependent on a DBLink?

有一个到远程数据库的 DBLink 和一个包 MY_PACKAGE(在本地模式中)通过 MY_VIEW 间接依赖于它。

当 DBLink 无效时(无论出于何种原因,即连接丢失或远程凭据被更改),包将无效。但是让它工作会很棒,因为除了通过此 DBLink 进行协商之外,此程序包还有其他职责。总的来说,我认为模式对象有效性取决于网络连接等不稳定部分并不是一个理想的情况。

我在遗留代码中发现了这种情况(参见 MY_PACKAGE.doSomething()),我什至不确定这是否是正确的设计。您能谈谈您对此的看法吗?

即使某些 DBLink 不可用,使包保持有效状态的正确方法是什么?

例如,使用引用 MY_VIEW 的动态游标是否正确,它仅在 DBLink 不正常(即 MY_PACKAGE.doSomethingAgain())时无法打开。当然,也许有更自然的方法来解决这个问题。我很高兴听到所有适合在 Oracle 中安全使用 DBLinks 的选项。

代码:

-- DBLink --------------------------------------------------------------
CREATE DATABASE LINK "MY_LINK"
CONNECT TO "MY_USER" IDENTIFIED BY VALUES ':1' USING 'WHATEVER';
------------------------------------------------------------------------

-- Synonym -------------------------------------------------------------
CREATE OR REPLACE EDITIONABLE SYNONYM "MY_SYNONYM" 
FOR "MY_REMOTE_SCHEMA"."MY_REMOTE_VIEW"@"MY_LINK";
------------------------------------------------------------------------

-- View ----------------------------------------------------------------
CREATE OR REPLACE VIEW "MY_VIEW" AS 
SELECT a,b,c FROM "MY_SYNONYM";

> Compiler Error    
>   ORA-02063: preceding 2 lines from MY_LINK
>  ORA-01017: invalid username/password; logon denied
>  [Oracle][ODBC SQL Server Wire Protocol driver][SQL Server]
>  Login failed for user 'MY_USER'. {28000,NativeErr = 18456}
------------------------------------------------------------------------

.

-- Package body --------------------------------------------------------
CREATE OR REPLACE PACKAGE BODY MY_PACKAGE AS
  
    PROCEDURE doSomething()
    IS
      i NUMBER := 0;
    BEGIN  
      FOR rec IN (SELECT * FROM "MY_VIEW")
      LOOP
        i := i + 1;
      END LOOP;
    END;
  
    PROCEDURE doSomethingAgain()
    IS
      i NUMBER := 0;
      my_cur SYS_REFCURSOR;
    BEGIN  

      OPEN my_cur FOR 'SELECT * FROM MY_VIEW';
      
      LOOP
        FETCH my_cur -- ...

        -- etc ...

        i := i + 1;
      END LOOP;
    END;
END MY_PACKAGE;

> Compiler Error
> 7/4   PL/SQL: SQL Statement ignored
> 7/35  PL/SQL: ORA-04063: view "MY_VIEW" has errors
------------------------------------------------------------------------

你最好的选择是让数据库链接保持活跃,我想。


另一种选择是移动过程 - 使用那些可疑的数据库链接 - out 并使它们成为独立的存储过程,这样如果它们变得无效,只有 它们 无效(而不是整个包),或者 - 可能 - 将那些程序(具有相同的命运)放入单独的包中。


还有一个选择是使用动态 SQL,因为在您真正尝试使用它们之前,Oracle 并不关心所涉及的任何对象是否有效。像这样:

SQL> create database link my_link
  2  connect to whoever
  3  identified by whatever
  4  using 'database_that_does_not_exist';

Database link created.

SQL> create or replace view my_view as
  2  select * from some_table@my_link;
select * from some_table@my_link
                         *
ERROR at line 2:
ORA-12154: TNS:could not resolve the connect identifier specified


SQL> create or replace procedure my_proc as
  2    l_id number;
  3  begin
  4    select id into l_id
  5    from my_view;
  6  end;
  7  /

Warning: Procedure created with compilation errors.

SQL> show err
Errors for PROCEDURE MY_PROC:

LINE/COL ERROR
-------- -----------------------------------------------------------------
4/3      PL/SQL: SQL Statement ignored
5/8      PL/SQL: ORA-00942: table or view does not exist

但是,动态 SQL:

SQL> create or replace procedure my_proc as
  2    l_id number;
  3  begin
  4    execute immediate 'select id from my_view' into l_id;
  5  end;
  6  /

Procedure created.

SQL>

看起来不错,但时间不长:

SQL> exec my_proc;
BEGIN my_proc; END;

*
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at "SCOTT.MY_PROC", line 4
ORA-06512: at line 1


SQL>

是的,我知道 - 并非所有代码都足够简单,可以将其放入动态 SQL。它越大,你必须维护它的问题就越严重,所以这只是我真的不想使用的可能性。