Znikające atrybuty sesji

Programiści piszący programy korzystające z Oracle, dość często wykorzystują polecenie ALTER SESSION. Jednym z najpopularniejszych zastosowań jest ustawianie pożądanego formatu daty czy liczb zmiennoprzecinkowych. Cóż za wygoda, napisać

   ALTER SESSION 
     SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS';

i dostawać daty w sensownym formacie. Oczywiście zastosowania ALTER SESSION się na tym nie wyczerpują, dostępnych atrybutów jest wiele - od poziomu izolacji transakcji do sposobu obsługi więzów integralności czy aktywności lub nie Oraclowego trace.

Problem w tym, że...

Począwszy od Oracle 8i, ustawienia ALTER SESSION mogą być nietrwałe!

O co chodzi? Ano, o dodaną od Oracle 8i nową funkcjonalność. W starszych wersjach Oracle, w razie restartu bazy danych czy zerwania połączenia sieciowego, funkcje biblioteczne Oracle zgłaszały błędy (choćby niezwykle intuicyjny komunikat 'rozszerzenie hostdef nie istnieje') i wymagały ponownego nawiązania połączenia z bazą danych explicite przez kod programu. Program dostawał błąd, restartował lub reinicjował się, przy okazji łączenia z bazą ponownie ustawiał charakterystyki sesji. Począwszy od Oracle 8i, procedury biblioteczne potrafią samodzielnie, nie angażując naszego kodu, "odzyskać" połaczenie z bazą danych! Dzięki temu, program może w ogóle nie zauważyć restartu bazy danych czy problemów z siecią - jeśli akurat w chwili ich wystąpienia nie wykonywał aktywnych operacji na bazie.

Piękne? Prawie. Bo owo nawiązane ponownie połączenie jest nową sesją, w której nie obowiązują już atrybuty ustalone wcześniej przez ALTER SESSION. I - na przykład - program zaczyna generować daty w formacie 2001/11/03 zamiast 2001-11-03 13:34:17. Albo zmienia logikę weryfikacji więzów integralności. Albo... Pół biedy, gdy spowoduje to błędy (choć tu też możemy mieć kłopot, jeżeli błędy 'klasyfikujemy' na mniej i bardziej fatalne, problemy które tu wystąpią możemy uznać za chwilowe i nie wymagające restartu). Gorzej, gdy np. ważny wyciąg z bazy danych wykona się z powodzeniem ale obetnie czas na dniach miesiąca.

Jak sobie z tym radzić? Cóż, zależy od sytuacji i od tego jakich atrybutów sesji akurat używamy.

  1. Wiele z domyślnych wartości atrybutów sesji można ustalić w pliku init.ora. Jeśli mamy nad nim kontrolę, jeśli wszystkie programy korzystające z danej bazy mają te same potrzeby - można na tym polegać. W takim wypadku warto zweryfikować przy starcie programu czy wszystko się zgadza, by po jakiejś wykonanej za dwa lata migracji bazy nie pojawiły się nagłe problemy.
  2. Niekiedy z atrybutów sesji można po prostu zrezygnować. Zapisy UPDATE sometable SET somedate = TO_DATE(:some_date, "YYYY-MM-DD HH24:MI:SS") WHERE id = :id czy SELECT TO_CHAR(:some_date, "YYYY-MM-DD HH24:MI:SS") FROM sometable nie są może najprzyjemniejsze w wpisywaniu ale zapewniają odpowiednią porcję świętego spokoju.
  3. Można próbować otrzymać powiadomienie o odnowieniu sesji. Biblioteka OCI zawiera funkcje pozwalające na zarejestrowanie odpowiedniego call-backa. W najprostszym wypadku można obsługując go zakończyć program, niejako przywracając w ten sposób dotychczasową semantykę.

I jeszcze uwaga dodatkowa: w podobnej sytuacji (restart bazy danych) spotkałem się z zgłaszaniem dość dziwnych błędów przez re-używane polecenia SQL (sytuacja, gdy tworzymy reprezentację pojedynczego SQLa/kursora i wielokrotnie, wiążąc różne parametry, go wykonujemy). Może być bezpieczniej z takich obiektów zrezygnować.

Wniosek końcowy? Pisząc programy korzystające z Oracle, warto przetestować ich zachowanie przy restarcie bazy danych. Zwykle wystarczy uruchomić program, pozwolić mu trochę podziałać, a następnie - w chwili bezczynności - zamknąć (shutdown abort) i ponownie uruchomić bazę danych.

komentarze obsługiwane przez Disqus