plsql
Obsługa wyjątków
Szukaj…
Wprowadzenie
Oracle tworzy szereg wyjątków. Możesz być zaskoczony, jak żmudne może być zatrzymanie kodu z niejasną wiadomością. Aby poprawić zdolność kodu PL / SQL do łatwej naprawy, należy obsługiwać wyjątki na najniższym poziomie. Nigdy nie ukrywaj wyjątku „pod dywan”, chyba że jesteś tutaj, aby zachować swój kod tylko dla siebie i dla nikogo innego.
Obsługa wyjątków
Co to jest wyjątek?
Wyjątkiem w PL / SQL jest błąd powstały podczas wykonywania programu.
Mamy trzy rodzaje wyjątków:
- Wewnętrznie zdefiniowane wyjątki
- Predefiniowane wyjątki
- Wyjątki zdefiniowane przez użytkownika
Co to jest obsługa wyjątków?
Obsługa wyjątków to możliwość utrzymania działania naszego programu, nawet jeśli pojawią się błędy w czasie wykonywania wynikające na przykład z błędów kodowania, awarii sprzętu. Unikamy gwałtownego zamykania programu.
Składnia
Ogólna składnia sekcji wyjątków:
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;
Sekcja wyjątków musi znajdować się na końcu bloku PL / SQL. PL / SQL daje nam możliwość zagnieżdżania bloków, wtedy każdy blok może mieć własną sekcję wyjątków, na przykład:
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;
Jeśli wyjątek zostanie zgłoszony w zagnieżdżonym bloku, należy go obsłużyć w wewnętrznej sekcji wyjątków, ale jeśli wewnętrzna sekcja wyjątków nie obsługuje tego wyjątku, ten wyjątek przejdzie do sekcji wyjątków zewnętrznego bloku.
Wewnętrznie zdefiniowane wyjątki
Wewnętrznie zdefiniowany wyjątek nie ma nazwy, ale ma własny kod.
Kiedy go używać?
Jeśli wiesz, że twoja operacja na bazie danych może powodować określone wyjątki od tych, które nie mają nazw, możesz nadać im nazwy, abyś mógł napisać procedury obsługi wyjątków specjalnie dla nich. W przeciwnym razie można ich używać tylko z others
modułami obsługi wyjątków.
Składnia
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;
to jest deklaracja nazwy wyjątku.
pragma exception_init(my_name_exc,-37);
przypisz nazwę do kodu błędu wewnętrznie zdefiniowanego wyjątku.
Przykład
Mamy emp_id, który jest kluczem podstawowym w tabeli emp i kluczem obcym w tabeli dept. Jeśli spróbujemy usunąć emp_id, gdy ma on rekordy potomne, zostanie zgłoszony wyjątek o kodzie -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;
/
Dokumentacja Oracle mówi: „Wewnętrznie zdefiniowany wyjątek z nazwą zadeklarowaną przez użytkownika jest nadal wewnętrznie zdefiniowanym wyjątkiem, a nie wyjątkiem zdefiniowanym przez użytkownika”.
Predefiniowane wyjątki
Predefiniowane wyjątki to wyjątki zdefiniowane wewnętrznie, ale mają nazwy. Baza danych Oracle automatycznie podnosi tego rodzaju wyjątki.
Przykład
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;
/
Poniżej znajdują się przykłady wyjątków z ich kodami:
Nazwa wyjątku | Kod błędu |
---|---|
NIE ZNALEZIONO DANYCH | -1403 |
ACCESS_INTO_NULL | -6530 |
CASE_NOT_FOUND | -6592 |
ROWTYPE_MISMATCH | -6504 |
TOO_MANY_ROWS | -1422 |
ZERO_DIVIDE | -1476 |
Pełna lista nazw wyjątków i ich kodów na stronie internetowej Oracle.
Wyjątki zdefiniowane przez użytkownika
Jak sama nazwa wskazuje, zdefiniowane przez użytkownika wyjątki są tworzone przez użytkowników. Jeśli chcesz utworzyć własny wyjątek, musisz:
- Zadeklaruj wyjątek
- Podnieś go ze swojego programu
- Utwórz odpowiedni moduł obsługi wyjątków, aby go złapać.
Przykład
Chcę zaktualizować wszystkie pensje pracowników. Ale jeśli nie ma pracowników, podnieś wyjątek.
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;
/
Co to znaczy raise
?
Serwer bazy danych zgłasza wyjątki automatycznie, gdy zajdzie taka potrzeba, ale jeśli chcesz, możesz jawnie zgłosić każdy wyjątek za pomocą raise
.
Procedura raise_application_error(error_number,error_message);
- numer_błędu musi wynosić od -20000 do -20999
- komunikat o błędzie wyświetlany, gdy wystąpi błąd.
Zdefiniuj niestandardowy wyjątek, podnieś go i zobacz, skąd pochodzi
Aby to zilustrować, oto funkcja, która ma 3 różne „złe” zachowania
- parametr jest całkowicie głupi: używamy wyrażenia zdefiniowanego przez użytkownika
- parametr ma literówkę: używamy standardowego błędu
NO_DATA_FOUND
Oracle - kolejna, ale nieobsługiwana sprawa
Dostosuj go do swoich standardów:
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;
/
Podanie w regularnej bazie danych:
[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
Pamiętaj, że wyjątek dotyczy rzadkich przypadków. Widziałem aplikacje, które zgłaszały wyjątek przy każdym dostępie, tylko po to, aby poprosić o hasło użytkownika, mówiąc „brak połączenia” ... tyle marnotrawstwa obliczeniowego.
Obsługa wyjątków błędów połączenia
Każdy standardowy błąd Oracle jest powiązany z numerem błędu. Ważne jest, aby przewidzieć, co może pójść nie tak w twoim kodzie. Tutaj w przypadku połączenia z inną bazą danych może to być:
-
-28000
konto jest zablokowane -
-28001
hasło wygasło -
-28002
okres karencji -
-1017
zły użytkownik / hasło
Oto sposób przetestowania, co poszło nie tak z użytkownikiem używanym przez łącze do bazy danych:
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;
/