我的架构上有一个AFTER CREATE触发器引发异常;我试图创建一个表。我知道未处理的异常可能会导致查询/操作/事务(我无法找到适用于此情况的单词)来终止。但是,当创建表后引发异常时,那么该表是否已经创建了?
成功触发后创建表时,会抛出错误错误:
create table test(testcol number);
错误:
SQL Error: ORA-00604: error occurred at recursive SQL level 1
ORA-06510: PL/SQL: unhandled user-defined exception
ORA-06512: at line 4
触发器:
create or replace trigger ddl_trig_2812
after create
on schema
declare
eirit exception;
begin
raise eirit;
end;
/
答案 0 :(得分:2)
事务以CREATE TABLE开头;然后AFTER CREATE触发器触发并引发异常,即表定义不会被提交"到数据字典表(例如USER_TABLES,USER_TAB_COLUMNS,......)但是"回滚"。
所以 - 不,CREATE TABLE流程还没有正确完成,你不能使用该表,因为它没有被创建,因为它的创建被触发器阻止了。
答案 1 :(得分:2)
来自文档:
在大多数情况下,如果触发器运行引发异常的语句,并且异常不由异常处理程序处理,则数据库将回滚触发器及其触发语句的效果。
正如您的问题所暗示的那样,它并不会导致它终止。您未处理的异常导致触发语句 - 即create table
- 被回滚。 When talking about DDL statements:
在数据库执行DDL语句之前发生隐式COMMIT,之后立即发生COMMIT或ROLLBACK。在前面的示例中,... [if] ALTER TABLE语句成功,然后数据库提交此语句;否则,数据库回滚此语句。 ...
所以这是预期的行为。
答案 2 :(得分:1)
验证这一点的一个好例子是检查表是否实际存在于触发器中。
让我们从RAISE
块中EXCEPTION
并查询DBA_OBJECTS
以查看对象是否存在。
SQL> create or replace trigger ddl_trig_2812
2 after create
3 on schema
4 declare
5 v_table_name DBA_OBJECTS.OBJECT_NAME%TYPE;
6 eirit exception;
7 begin
8 select object_name into v_table_name from DBA_OBJECTS where object_name = 'ATEST';
9 raise eirit;
10 EXCEPTION
11 WHEN OTHERS THEN
12 DBMS_OUTPUT.PUT_LINE( 'TABLE CREATED '|| v_table_name );
13 RAISE;
14 END;
15
16 /
创建了触发器。
现在,让我们创建表格。
SQL> set serveroutput on;
SQL> create table atest ( a number);
TABLE CREATED ATEST
create table atest ( a number)
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 1
ORA-06510: PL/SQL: unhandled user-defined exception
ORA-06512: at line 10
虽然引发了异常,但该表存在于数据字典中,您可以在dbms_output
显示的消息上方看到。
现在,如果我们检查表是否存在,
SQL> select * from atest;
select * from atest
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL> select object_name from DBA_OBJECTS where object_name = 'ATEST'
2 ;
no rows selected
这意味着,Oracle会更改DDL触发器中的数据字典,但如果触发器中发生错误,则会回滚事务。