我对
有误解PRAGMA AUTONOMOUS_TRANSACTION
指令。
据我所知,它用于日志记录或审计过程中,由主程序(自治程序,过程,函数或触发器)独立运行。
我在生成DUP_VAL_ON_INDEX的表上有一个UPDATE。在这种情况下,我调用了一个记录过程,该过程将错误记录到表中。在日志记录过程中,我没有指定PRAGMA AUTONOMOUS_TRANSACTION指令,但它仍会在我的日志记录表中进行插入。
这是我的代码:
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指令,谁能解释我为什么它仍然记录我的错误,并提供一个示例,其中没有记录代码?
谢谢
答案 0 :(得分:2)
谁能解释我为什么它仍然记录我的错误并提供一个 如果未指定PRAGMA,则不会记录代码的示例 请问AUTONOMOUS_TRANSACTION指令?
由于您将其作为Inserted
处理,因此错误在Log
表中的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;
输出:
输出将在Update
事务中完成Autonomous
。在main
块中完成的更新将是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
答案 1 :(得分:0)
PKG_LOGGING.PRC_LOG()有一个commit语句,因此它将提交。
假设您的代码看起来像这样:
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;
在某些情况下,如果我们无法记录重要信息,我们肯定希望停止我们的流程。但是有时我们希望日志正常运行。例如,如果它不能记录错误,我需要隔夜进行批处理运行,因为该日志是我知道什么(如果有的话)出现错误的唯一方法,因此最好不要运行整个记录不完全,我不知道有些事情失败了。但是,如果我只是在Test中编写一些跟踪消息,则我可能更喜欢长时间运行的过程以没有完整的跟踪集来结束而不是终止,因为日志表空间不足。
此外,也不需要使用raise_application_error()
。在回滚后只需发出raise;
即可完成。