为什么它在没有 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
事务中完成 Update
。 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
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;
即可完成。
我对
有误解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
事务中完成 Update
。 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
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;
即可完成。