如果我创建了这个触发器,那么当在表上使用drop或truncate时会引发错误,但是没有任何内容插入到logTable中,但是如果我删除了RAISE_APPLICATION_ERROR ...则将值插入到logTable中,但是drop / truncate也被执行。为什么?如何避免在Schema上删除/截断(如果我使用而不是触发器,只有在架构的所有者正在删除/截断某些内容时才会触发它)。
CREATE OR REPLACE TRIGGER trigger_name
BEFORE DROP OR TRUNCATE ON DATABASE
DECLARE
username varchar2(100);
BEGIN
IF ora_dict_obj_owner = 'MySchema' THEN
select user INTO username from dual;
INSERT INTO logTable VALUES(username , SYSDATE);
RAISE_APPLICATION_ERROR (-20001,'ERROR, YOU CAN NOT DELETE THIS!!');
END IF;
END;
答案 0 :(得分:1)
声明级原子性
Oracle数据库支持语句级原子性,这意味着SQL语句是一个原子工作单元 并且要么完全成功要么完全失败。
成功的声明与已提交的事务不同。一个 如果数据库解析和,则单个SQL语句成功执行 在没有错误的情况下运行它作为原子单元,就像所有行都被更改一样 在多行更新中。
如果SQL语句在执行期间导致错误,则不会 成功,所以声明的所有效果都会被回滚。这个 operation是语句级回滚。
该过程是PL / SQL语句,它是原子的,如果在过程中引发错误,则整个过程失败,Oracle会执行此过程完成的所有更改的回滚。
但您可以使用AUTONOMOUS_TRANSACTION Pragma创建一个过程,以便以这种方式绕过此行为:
CREATE TABLE logtable(
username varchar2(200),
log_date date
);
CREATE OR REPLACE PROCEDURE log_message( username varchar2 ) IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO logtable( username, log_date ) VALUES ( username, sysdate );
COMMIT;
END;
/
CREATE OR REPLACE TRIGGER trigger_name
BEFORE DROP OR TRUNCATE ON DATABASE
DECLARE
username varchar2(100);
BEGIN
IF ora_dict_obj_owner = 'TEST' THEN
log_message( user );
RAISE_APPLICATION_ERROR (-20001,'ERROR, YOU CAN NOT DELETE THIS!!');
END IF;
END;
现在:
drop table table1;
ORA-00604: error occurred at recursive SQL level 1
ORA-20001: ERROR, YOU CAN NOT DELETE THIS!!
ORA-06512: at line 6
00604. 00000 - "error occurred at recursive SQL level %s"
*Cause: An error occurred while processing a recursive SQL statement
(a statement applying to internal dictionary tables).
*Action: If the situation described in the next error on the stack
can be corrected, do so; otherwise contact Oracle Support.
select * from logtable;
USERNAME LOG_DATE
-------- -------------------
TEST 2018-04-27 00:16:34