我最近发布了一个使用 DBLinks 和监视无效对象的问题。现在我必须制作一个表并按日期注册所有无效对象,并在该代码的运行之间进行比较,如果有任何更改(对象更改其状态,有新对象等),代码将打印更改,例如这个:
DBLink 1:
(changes found)
DBLink 2:
No changes
.
.
.
Consecutively
为此我创建了一个表
CREATE TABLE Invalid_Objects (
id NUMBER PRIMARY KEY,
alias VARCHAR2(30),
user_db_links VARCHAR2(128),
owner VARCHAR2(128),
object_name VARCHAR2(128),
status VARCHAR2(30),
object_type VARCHAR2(64),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
last_checked_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
我使用的代码是:
-- We enable server output in the SQL client.
SET SERVEROUTPUT ON
DECLARE
CURSOR cur_previous_results IS
SELECT owner, object_name, status, object_type
FROM Invalid_Objects
WHERE alias = (SELECT MAX(alias) FROM Invalid_Objects);
TYPE obj_details_type IS RECORD (
owner VARCHAR2(128),
object_name VARCHAR2(128),
status VARCHAR2(30),
object_type VARCHAR2(64)
);
TYPE obj_details_table IS TABLE OF obj_details_type;
obj_details_list obj_details_table := obj_details_table();
v_db_link_name VARCHAR2(128);
v_row_count NUMBER := 0;
v_current_alias VARCHAR2(30);
v_previous_alias VARCHAR2(30);
v_object_found NUMBER; -- Variable to store the search state of the object
BEGIN
v_current_alias := TO_CHAR(SYSDATE, 'YYYYMMDDHH24MISS');
SELECT MAX(alias) INTO v_previous_alias FROM Invalid_Objects;
FOR rec_link IN (SELECT db_link FROM user_db_links) LOOP
v_db_link_name := rec_link.db_link;
BEGIN
EXECUTE IMMEDIATE 'SELECT owner, object_name, status, object_type
FROM dba_objects@'||rec_link.db_link||'
WHERE status = ''INVALID'''
BULK COLLECT INTO obj_details_list;
FOR i IN 1 .. obj_details_list.COUNT LOOP
v_row_count := v_row_count + 1;
INSERT INTO Invalid_Objects (id, alias, user_db_links, owner, object_name, status, object_type)
VALUES (v_row_count, v_current_alias, v_db_link_name, obj_details_list(i).owner, obj_details_list(i).object_name, obj_details_list(i).status, obj_details_list(i).object_type);
END LOOP;
IF v_previous_alias IS NOT NULL THEN
dbms_output.put_line('Comparing with previous run (alias: ' || v_previous_alias || '):');
FOR rec_current IN (SELECT owner, object_name, status, object_type FROM Invalid_Objects WHERE alias = v_current_alias) LOOP
-- We initialize v_object_found to 0 (false)
v_object_found := 0;
-- We move the cursor cur_previous_results to find the current object
FOR rec_previous IN cur_previous_results LOOP
IF rec_previous.owner = rec_current.owner AND rec_previous.object_name = rec_current.object_name THEN
-- If we find the current object in the results above, we set v_object_found to 1 (true)
v_object_found := 1;
EXIT;
END IF;
END LOOP;
-- If v_object_found is 0, the current object was not found in the previous results and is considered new
IF v_object_found = 0 THEN
dbms_output.put_line('New object: ' || rec_current.object_name);
END IF;
END LOOP;
ELSE
dbms_output.put_line('There is no previous run to compare.');
END IF;
-- Close database link inside FOR loop
dbms_session.close_database_link(v_db_link_name);
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Error running dynamic query for link ' || v_db_link_name || ': ' || SQLERRM);
dbms_session.close_database_link(v_db_link_name); -- we close the link in case of error
END;
END LOOP;
-- Commit after closing all links
COMMIT;
EXCEPTION
WHEN OTHERS THEN -- We do not allow a mistake to break the cycle, it continues
dbms_output.put_line(v_db_link_name || ' errored: ' || SQLERRM);
END;
/
但它只打印这个错误:
There is no previous run to compare.
Error executing dynamic query for DBLINK link:
ORA-02080: database link is in use
DBLINK errored: ORA-02080: database link is in
use
PL/SQL procedure completed successfully.
我的推理正确吗,还是有其他方法可以关闭 DBLinks?
在尝试关闭会话在当前事务中使用的链接之前,您需要发出
COMMIT
,即使它只是一个 SELECT
语句。然后它会让你关闭链接。
COMMIT; -- add here
dbms_session.close_database_link(v_db_link_name);
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Error running dynamic query for link ' || v_db_link_name || ': ' || SQLERRM);
COMMIT; -- and here
dbms_session.close_database_link(v_db_link_name); -- we close the link in case of error
END;