plsql
Undantagshantering
Sök…
Introduktion
Oracle producerar olika undantag. Du kan bli förvånad över hur tråkigt det kan vara att stoppa din kod med något oklart meddelande. För att förbättra din PL / SQL-kod förmåga att enkelt fixas är det nödvändigt att hantera undantag på den lägsta nivån. Göm aldrig ett undantag "under mattan", såvida du inte är här för att hålla din kodkod bara för dig och för ingen annan att underhålla.
De fördefinierade felen .
Undantagshantering
Vad är ett undantag?
Undantag i PL / SQL är ett fel skapat under ett programkörning.
Vi har tre typer av undantag:
- Internt definierade undantag
- Fördefinierade undantag
- Användardefinierade undantag
Vad är ett undantagshantering?
Undantagshantering är en möjlighet att hålla vårt program igång även om det visas runtime-fel som beror på till exempel kodningsfel, maskinvarufel. Vi undviker att det går ur plötsligt.
Syntax
Den allmänna syntaxen för undantagsavsnitt:
declare
declaration Section
begin
some statements
exception
when exception_one then
do something
when exception_two then
do something
when exception_three then
do something
when others then
do something
end;
Ett undantagsavsnitt måste vara i slutet av PL / SQL-blocket. PL / SQL ger oss möjlighet att häcka block, då kan varje block ha sitt eget undantagsavsnitt till exempel:
create or replace procedure nested_blocks
is
begin
some statements
begin
some statements
exception
when exception_one then
do something
end;
exception
when exception_two then
do something
end;
Om undantag kommer att höjas i det kapslade blocket ska det hanteras i det inre undantagsavsnittet, men om det inre undantagsavsnittet inte hanterar detta undantag kommer detta undantag att gå till undantagsavsnittet i det externa blocket.
Internt definierade undantag
Ett internt definierat undantag har inte ett namn, men det har sin egen kod.
När ska man använda den?
Om du vet att din databasoperation kan höja specifika undantag de som inte har namn, kan du ge dem namn så att du kan skriva undantagshanterare specifikt för dem. Annars kan du använda dem bara med others
undantagshanterare.
Syntax
declare
my_name_exc exception;
pragma exception_init(my_name_exc,-37);
begin
...
exception
when my_name_exc then
do something
end;
my_name_exc exception;
det är undantagsnamndeklarationen.
pragma exception_init(my_name_exc,-37);
tilldela namn till felkoden för internt definierat undantag.
Exempel
Vi har en emp_id som är en primär nyckel i emp-tabellen och en främmande nyckel i avd-tabellen. Om vi försöker ta bort emp_id när det har underordnade poster kommer det att kastas ett undantag med kod -2292.
create or replace procedure remove_employee
is
emp_exception exception;
pragma exception_init(emp_exception,-2292);
begin
delete from emp where emp_id = 3;
exception
when emp_exception then
dbms_output.put_line('You can not do that!');
end;
/
Oracle-dokumentationen säger: "Ett internt definierat undantag med ett användardeklarerat namn är fortfarande ett internt definierat undantag, inte ett användardefinierat undantag."
Fördefinierade undantag
Fördefinierade undantag är internt definierade undantag men de har namn. Oracle-databasen höjer denna typ av undantag automatiskt.
Exempel
create or replace procedure insert_emp
is
begin
insert into emp (emp_id, ename) values ('1','Jon');
exception
when dup_val_on_index then
dbms_output.put_line('Duplicate value on index!');
end;
/
Nedan följer exempel på undantag med deras koder:
Undantag Namn | Felkod |
---|---|
INGEN INFORMATION HITTAD | -1403 |
ACCESS_INTO_NULL | -6530 |
CASE_NOT_FOUND | -6592 |
ROWTYPE_MISMATCH | -6504 |
TOO_MANY_ROWS | -1422 |
ZERO_DIVIDE | -1476 |
Fullständig lista över undantagsnamn och deras koder på Oracle-webbplatsen.
Användardefinierade undantag
Som namnet antyder användardefinierade undantag skapas av användare. Om du vill skapa ditt eget undantag måste du:
- Förklara undantaget
- Höj det från ditt program
- Skapa lämplig undantagshanterare för att fånga honom.
Exempel
Jag vill uppdatera alla arbetares löner. Men om det inte finns några arbetare, höja ett undantag.
create or replace procedure update_salary
is
no_workers exception;
v_counter number := 0;
begin
select count(*) into v_counter from emp;
if v_counter = 0 then
raise no_workers;
else
update emp set salary = 3000;
end if;
exception
when no_workers then
raise_application_error(-20991,'We don''t have workers!');
end;
/
Vad betyder det raise
?
Undantag tas upp av databaseservern automatiskt när det finns ett behov, men om du vill kan du höja uttryckligen alla undantag med raise
.
Procedur raise_application_error(error_number,error_message);
- felnummer måste vara mellan -20000 och -20999
- error_message-meddelande som ska visas när fel uppstår.
Definiera anpassat undantag, höja det och se var det kommer ifrån
För att illustrera detta är här en funktion som har 3 olika "fel" beteenden
- parametern är helt dum: vi använder ett användardefinierat uttryck
- parametern har en skrivfel: vi använder Oracle standard
NO_DATA_FOUND
fel - ett annat, men inte hanterat ärende
Anpassa dig gärna till dina standarder:
DECLARE
this_is_not_acceptable EXCEPTION;
PRAGMA EXCEPTION_INIT(this_is_not_acceptable, -20077);
g_err varchar2 (200) := 'to-be-defined';
w_schema all_tables.OWNER%Type;
PROCEDURE get_schema( p_table in Varchar2, p_schema out Varchar2)
Is
w_err varchar2 (200) := 'to-be-defined';
BEGIN
w_err := 'get_schema-step-1:';
If (p_table = 'Delivery-Manager-Is-Silly') Then
raise this_is_not_acceptable;
end if;
w_err := 'get_schema-step-2:';
Select owner Into p_schema
From all_tables
where table_name like(p_table||'%');
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- handle Oracle-defined exception
dbms_output.put_line('[WARN]'||w_err||'This can happen. Check the table name you entered.');
WHEN this_is_not_acceptable THEN
-- handle your custom error
dbms_output.put_line('[WARN]'||w_err||'Please don''t make fun of the delivery manager.');
When others then
dbms_output.put_line('[ERR]'||w_err||'unhandled exception:'||sqlerrm);
raise;
END Get_schema;
BEGIN
g_err := 'Global; first call:';
get_schema('Delivery-Manager-Is-Silly', w_schema);
g_err := 'Global; second call:';
get_schema('AAA', w_schema);
g_err := 'Global; third call:';
get_schema('', w_schema);
g_err := 'Global; 4th call:';
get_schema('Can''t reach this point due to previous error.', w_schema);
EXCEPTION
When others then
dbms_output.put_line('[ERR]'||g_err||'unhandled exception:'||sqlerrm);
-- you may raise this again to the caller if error log isn't enough.
-- raise;
END;
/
Ger en vanlig databas:
[WARN]get_schema-step-1:Please don't make fun of the delivery manager.
[WARN]get_schema-step-2:This can happen. Check the table name you entered.
[ERR]get_schema-step-2:unhandled exception:ORA-01422: exact fetch returns more than requested number of rows
[ERR]Global; third call:unhandled exception:ORA-01422: exact fetch returns more than requested number of rows
Kom ihåg att undantag är här för att hantera sällsynta fall. Jag såg applikationer som tog upp ett undantag vid varje åtkomst, bara för att be om användarlösenordet och säga "inte ansluten" ... så mycket beräkningsavfall.
Hantera undantag för anslutningsfel
Varje Oracle-standardfel är associerat med ett felnummer. Det är viktigt att förutse vad som kan gå fel i din kod. Här för en anslutning till en annan databas kan det vara:
-
-28000
kontot är låst -
-28001
lösenord löpt ut -
-28002
-
-1017
fel användare / lösenord
Här är ett sätt att testa vad som går fel med den användare som används av databaslänken:
declare
v_dummy number;
begin
-- testing db link
execute immediate 'select COUNT(1) from [email protected]' into v_dummy ;
-- if we get here, exception wasn't raised: display COUNT's result
dbms_output.put_line(v_dummy||' users on PASS db');
EXCEPTION
-- exception can be referred by their name in the predefined Oracle's list
When LOGIN_DENIED
then
dbms_output.put_line('ORA-1017 / USERNAME OR PASSWORD INVALID, TRY AGAIN');
When Others
then
-- or referred by their number: stored automatically in reserved variable SQLCODE
If SQLCODE = '-2019'
Then
dbms_output.put_line('ORA-2019 / Invalid db_link name');
Elsif SQLCODE = '-1035'
Then
dbms_output.put_line('ORA-1035 / DATABASE IS ON RESTRICTED SESSION, CONTACT YOUR DBA');
Elsif SQLCODE = '-28000'
Then
dbms_output.put_line('ORA-28000 / ACCOUNT IS LOCKED. CONTACT YOUR DBA');
Elsif SQLCODE = '-28001'
Then
dbms_output.put_line('ORA-28001 / PASSWORD EXPIRED. CONTACT YOUR DBA FOR CHANGE');
Elsif SQLCODE = '-28002'
Then
dbms_output.put_line('ORA-28002 / PASSWORD IS EXPIRED, CHANGED IT');
Else
-- and if it's not one of the exception you expected
dbms_output.put_line('Exception not specifically handled');
dbms_output.put_line('Oracle Said'||SQLCODE||':'||SQLERRM);
End if;
END;
/