为什么它在没有 PRAGMA 的情况下工作 AUTONOMOUS_TRANSACTION

why it is working without PRAGMA AUTONOMOUS_TRANSACTION

我对

有误解

PRAGMA AUTONOMOUS_TRANSACTION

指令。

据我所知,它被用于日志记录或审计程序,运行 独立于主程序(自治、过程、函数或触发器)。

我有一个 table 的更新生成 DUP_VAL_ON_INDEX。在此异常中,我调用了一个将错误记录到 table 中的记录过程。在日志记录过程中,我没有指定 PRAGMA AUTONOMOUS_TRANSACTION 指令,但它仍然在我的日志记录中插入 table.

这是我的代码:

create table TEST_PRAGMA
    ( COL_1 number primary key
    , COL_2 number
    );

--
insert into TEST_PRAGMA values (1, 200);
insert into TEST_PRAGMA values (2, 200);
--
create table T_LOG    
    ( msg_num number primary key
    , MSG_DATE timestamp(6)
    , INFO_MSG varchar2(10)
    , LONG_MSG varchar2(100)
    );
--    
create sequence SEQ_TEST start with 1 increment by 1 nocache nocycle;

包裹:

create or replace package pkg_logging as

    procedure PRC_LOG ( P_MSG_NUM number 
                      , P_MSG_DATE timestamp
                      , P_INFO_MSG varchar2
                      , p_long_msg varcahr2);
end PKG_LOGGING;
--
create or replace package body pkg_logging as

    procedure PRC_LOG ( P_MSG_NUM number 
                      , P_MSG_DATE timestamp
                      , P_INFO_MSG varchar2
                      , P_LONG_MSG VARCHAR2)
                      as
    begin

        insert into T_LOG
            ( MSG_NUM
            , MSG_DATE
            , INFO_MSG
            , LONG_MSG
            )
        values
            ( P_MSG_NUM 
            , P_MSG_DATE
            , P_INFO_MSG
            , P_LONG_MSG

            );
        commit;
    EXCEPTION
        when OTHERS then
            rollback;
            RAISE_APPLICATION_ERROR(-20000, 'other error has occured: ' || sqlcode || ' - ' || sqlerrm);
    end PRC_LOG;
end PKG_LOGGING;
--
set SERVEROUTPUT on;
begin

    update TEST_PRAGMA set COL_1 = 1 where COL_2 = 200;
    commit;

EXCEPTION
    when DUP_VAL_ON_INDEX then 
    dbms_output.put_line ('DUP_VAL_ON_INDEX error has occured');
        PKG_LOGGING.PRC_LOG(SEQ_TEST.NEXTVAL, systimestamp, 'error', 'test de logging');
        rollback;
end;

因为我没有指定 PRAGMA 指令,所以我希望即使逻辑正确也不会记录错误。

如果我没有指定 PRAGMA AUTONOMOUS_TRANSACTION 指令,谁能解释一下为什么它仍然记录我的错误并提供一个示例,它不记录代码,好吗?

谢谢,

Can anyone explain me why it is still logs my error and provide a sample where it does not log the code if I do not specify the PRAGMA AUTONOMOUS_TRANSACTION directive, please?

错误是 Inserted in Log table,因为您将其作为 Exception handling 处理。您需要将 AUTONOMOUS 事务的行为理解为一段 Independent 代码,即使主调用 proc/pkg 失败也会执行该代码。它没有作为 Exception Handling 的一部分处理。如下面的演示所示,您可以看到标记为 AUTONOMOUS 的 proc 直接在 BEGIN 块中调用,而不是在 Exception 块中调用以了解行为。

DECLARE
    l_salary   NUMBER;
--Private Proc marking as Autonomous transaction 
procedure nested_block ‬ 
   as 
   pragma AUTONOMOUS_TRANSACTION;
   BEGIN
     UPDATE emp
     SET salary=salary+15000
     WHERE emp_no=1002;
    COMMIT;
    END;‭
--Main Block    ‬
BEGIN
SELECT salary 
INTO l_salary 
FROM emp 
WHERE emp_no=1001; 

Dbms_output.put_line('Before Salary of 1001 is'||l_salary); 

SELECT salary 
INTO l_salary 
FROM emp WHERE emp_no=1002;

Dbms_output.put_line('Before Salary of 1002 is '|| 1_salary);

UPDATE emp
    SET
        salary = salary + 5000
WHERE emp_no = 1001;

--Calling Autonomous transaction
nested_block;

--And rolling back previous updates.
ROLLBACK;

SELECT salary INTO
    l_salary
FROM emp
WHERE emp_no = 1001;

dbms_output.put_line('After Salary of 1001 is'|| l_salary);

SELECT salary 
INTO  l_salary
FROM emp
WHERE emp_no = 1002;

dbms_output.put_line('After Salary of 1002 is ' || l_salary);

end;

输出:

输出将在 Autonomous 事务中完成 Updatemain 块中完成的更新将是 rolledback 但不是 private proc 中标记为 Autonomous

的更新
Before Salary of 1001 is 15000 
Before Salary of 1002 is 10000 
After  Salary of 1001 is 15000 
After  Salary of 1002 is 25000 

PKG_LOGGING.PRC_LOG() 有一个提交语句,所以它会提交。

假设您的代码看起来像这样:

set SERVEROUTPUT on;
begin

    insert into TEST_PRAGMA values (3, 300);
    PKG_LOGGING.PRC_LOG(SEQ_TEST.NEXTVAL, systimestamp, 'info', 'inserted a record');

    update TEST_PRAGMA set COL_1 = 1 where COL_2 = 200;
    commit;

EXCEPTION
    when DUP_VAL_ON_INDEX then 
    dbms_output.put_line ('DUP_VAL_ON_INDEX error has occured');
        PKG_LOGGING.PRC_LOG(SEQ_TEST.NEXTVAL, systimestamp, 'error', 'test de logging');
        rollback;
end;

您在 TEST_PRAGMA 中有多少条记录? 三个。因为插入是在我们调用 PKG_LOGGING.PRC_LOG() 时提交的,因此异常处理程序中的回滚没有效果。这就是为什么我们应该在审计和日志例程中使用 PRAGMA AUTONOMOUS_TRANSACTION 的原因:这样我们就可以成功地保留我们的日志消息而不影响更广泛的事务。

因此您应该将 PRAGMA AUTONOMOUS_TRANSACTION 添加到 PKG_LOGGING.PRC_LOG()。


顺便说一下,我认为您应该小心日志包中的错误处理程序:

EXCEPTION
    when OTHERS then
        rollback;
        RAISE_APPLICATION_ERROR(-20000, 'other error has occured: ' || sqlcode || ' - ' || sqlerrm);
end PRC_LOG;

在某些情况下,如果我们无法记录重要信息,我们肯定希望停止我们的进程。但其他时候我们希望日志记录正常失败。例如,如果它不能记录错误,我需要通宵批处理 运行 异常终止,因为该日志是我知道什么(如果有的话)出错的唯一方式,而且整个事情最好不要 运行 它 运行 不完整,我不知道有些事情失败了。但是,如果我只是在测试中编写一些跟踪消息,我可能更喜欢漫长的 运行ning 过程在没有完整跟踪集的情况下结束而不是异常终止,因为日志记录 table 已经 运行 了space。

此外,没有必要使用 raise_application_error()。只需在回滚后发出 raise; 即可完成。