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



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

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

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

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

例如,使用引用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
------------------------------------------------------------------------

我认为,您最好的选择是保持数据库链接的活跃和活跃。


另一种选择是将使用这些可疑数据库链接的过程移该包,并使它们成为独立的存储过程,以便在它们无效时,只有它们无效(而不是整个包),或者 - 可能 - 将这些过程(共享相同的命运)放入单独的包中。


另一种选择是使用动态 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 中。它越大,你必须维护它的问题越严重,所以这只是我真的不想使用的可能性。

最新更新