BD-1st-2.4-lab10.tresc-1.1-Slajd6

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania

Wykonywanie zapytań

Wykonywanie zapytań


Po nawiązaniu połączenia, kolejnym krokiem jaki należy wykonać, jest utworzenie obiektu implementującego interfejs „Statement”. Jest to obiekt związany z konkretnym połączeniem, za pomocą którego JDBC wykonuje polecenia SQL w SZBD. Obiekt ten można utworzyć za pomocą bezparametrowej metody „createStatement” interfejsu „Connection”. Rozważmy przykład (1). Instrukcja przedstawiona na tym przykładzie rozpoczyna się od deklaracji zmiennej „stmt” typu „Statement”. Do tej zmiennej przypisywany jest następnie wynik działania metody „createStatement” aktywowanej na rzecz obiektu reprezentującego nawiązane połączenie (patrz poprzedni slajd). W wyniku instrukcji przedstawionej na przykładzie (1) w zmiennej „stmt” znajdzie się obiekt pozwalający na wykonywanie -poleceń SQL w SZBD.

Omawianie sposobów wykonywania poleceń SQL rozpoczniemy od omówienia metod pozwalających na wykonywanie zapytań do baz danych i odczytywanie ich wyników. Aby wykonać zapytanie należy użyć metody „executeQuery” interfejsu „Statement”. Jest to metoda, której jedynym parametrem jest łańcuch zawierający treść polecenia SELECT. Metoda „executeQuery” zwraca obiekt implementujący interfejs „ResultSet”, który reprezentuje otrzymany w wyniku zapytania zbiór krotek. Jeżeli przy wykonywaniu zadanego zapytania wystąpi problem, zgłaszany jest wyjątek „SQLException”. Sposób użycia metody executeQuery przedstawiono na przykładzie (2). Instrukcja na tym przykładzie rozpoczyna się od deklaracji zmiennej „rs” typu „ResultSet”, której przypisywany jest wynik działania metody „executeQuery”. Metoda „executeQuery” jest aktywowana na rzecz utworzonego wcześniej obiektu zapisanego w zmiennej „stmt”, który pozwala na wykonywanie poleceń SQL w SZBD. Metoda „executeQuery” przesyła zapytanie, przekazane jako parametr aktualny, do SZBD i zwraca obiekt reprezentujący zbiór krotek otrzymanych w wyniku zapytania. Zwróćmy uwagę na zapytanie przekazane jako parametr. Jest to proste zapytanie, którego zadaniem jest odszukanie nazwisk i płac wszystkich pracowników. Ciekawą rzeczą jest to, iż polecenie SQL nie jest zakończone średnikiem. Użycie tutaj średnika zakończyłoby się błędem i dlatego w JDBC nie należy używać średników do zakończenia polecenia SQL.

Obiekt otrzymany w wyniku działania metody „executeQuery” zawiera metody pozwalające na odczytanie wyniku zapytania. Obiekt ten jest rodzajem iteratora, którego wskaźnik, zaraz po wykonaniu zapytania, znajduje się przed pierwszą krotką wyniku. Aby przesunąć wskaźnik należy użyć metody „next”, która przesuwa wskaźnik na kolejną krotkę wyniku (lub pierwszą przy pierwszym wykonaniu). Metoda „next” zwraca wartość logiczną „true”, jeśli wskaźnik został przesunięty na prawidłową krotkę, bądź „false”, jeśli został przesunięty poza ostatnią krotkę. Dzięki zwracanym przez metodę „next” wartościom można użyć jej wywołania, jako warunku zakończenia pętli „while”, której celem jest przejrzenie całego wyniku zapytania (patrz przykład (3)). Kiedy wskaźnik wskazuje na poprawną krotkę, można odczytać wartości jej atrybutów za pomocą metod interfejsu „ResultSet”, o nazwach „getXXX”, gdzie XXX jest nazwą typu zwracanej wartości. Należy stosować odpowiednie metody „getXXX”, dla odpowiednich atrybutów, aby otrzymać wartości odpowiednich typów. Poniżej podano sugerowane metody „getXXX”, dla różnych typów SQL:

- „getString” (typ zwracanej wartości: „String”) :

Można użyć praktycznie dla każdego typu SQL, żeby otrzymać wartość atrybutu w postaci łańcucha. W ogólności jednak najlepiej stosować tą metodę dla typów: CHARACTER(n), CHAR(n), CHARACTER VARYING(n), CHAR VARYING(n), NATIONAL CHARACTER(n), NATIONAL CHAR(n), NATIONAL CHARACTER VARYING (n), NATIONAL CHAR VARYING(n), NCHAR VARYING(n). Jeżeli atrybut zawiera wartość NULL, to metoda zwraca wartość „null” (pusty wskaźnik w języku Java).

- „getShort” (typ zwracanej wartości: „short”):

Należy używać dla atrybutów całkowitoliczbowych, których wartości mieszczą się w przedziale <-32768,32767>. Sugerowane jest używanie tej metody dla atrybutów typu SMALLINT. Jeżeli atrybut zawiera wartość NULL zwracane jest 0.

- „getInt” (typ zwracanej wartości: „int”):

Należy używać dla atrybutów całkowitoliczbowych, których wartości mieszczą się w przedziale <-2147483648,2147484647>. Sugerowane jest używanie tej metody dla atrybutów typów: INTEGER i INT. Jeżeli atrybut zawiera wartość NULL zwracane jest 0.

- „getFloat” (typ zwracanej wartości: „float”):

Należy używać dla atrybutów przechowujących wartości liczbowe zmiennoprzecinkowe o pojedynczej precyzji. Sugerowane jest używanie tej metody dla atrybutów typu REAL. Jeżeli atrybut zawiera wartość NULL zwracane jest 0.

- „getDouble” (typ zwracanej wartości: „double”):

Należy używać dla atrybutów przechowujących wartości liczbowe zmiennoprzecinkowe o zwiększonej precyzji. Sugerowane jest używanie tej metody dla atrybutów typów FLOAT(b) i DOUBLE PRECISION. Jeżeli atrybut zawiera wartość NULL zwracane jest 0.

- „getBigDecimal” (typ zwracanej wartości: „java.math.BigDecimal”):

Należy używać dla atrybutów liczbowych o definiowanej przez użytkownika precyzji. Sugerowane jest używanie tej metody dla atrybutów typów NUMERIC(p,s) i DECIMAL (p,s). Jeżeli atrybut zawiera wartość NULL, to metoda zwraca wartość „null” (pusty wskaźnik w języku Java).

  • „getTimestamp” (typ zwracanej wartości: „java.sql.Timestamp”):

Należy używać dla atrybutów typu zezwalającego na przechowywanie zarówno dat jak i czasu. Sugerowane jest używanie tej metody dla atrybutów typu TIMESTAMP(n) i DATE (w SZBD Oracle). Jeżeli atrybut zawiera wartość NULL, to metoda zwraca wartość „null” (pusty wskaźnik w języku Java).

- „getDate” (typ zwracanej wartości: „java.sql.Date”):

Należy używać dla atrybutów przechowujących daty. Sugerowane jest używanie tej metody dla atrybutów typu DATE (za wyjątkiem SZBD Oracle). Jeżeli atrybut zawiera wartość NULL, to metoda zwraca wartość „null” (pusty wskaźnik w języku Java).

- „getTime” (typ zwracanej wartości: „java.sql.Time”):

Należy używać dla atrybutów przechowujących czas. Sugerowane jest używanie tej metody dla atrybutów typu TIME(n). Jeżeli atrybut zawiera wartość NULL, to metoda zwraca wartość „null” (pusty wskaźnik w języku Java).

- „getBlob” (typ zwracanej wartości „java.sql.Blob”):

Należy używać dla atrybutów typu BLOB. Jeżeli atrybut zawiera wartość NULL, to metoda zwraca wartość „null” (pusty wskaźnik w języku Java).

- „getClob” (typ zwracanej wartości „java.sql.Clob”):

Należy używać dla atrybutów typu CLOB. Jeżeli atrybut zawiera wartość NULL, to metoda zwraca wartość „null” (pusty wskaźnik w języku Java).

Dla typu INTERVAL nie przewidziano w JDBC odpowiednich metod ani typów. Istnieją rozwiązania specyficzne dla producentów konkretnych SZBD, jednak nie będziemy ich opisywać. W ogólności możliwe jest używanie innych niż sugerowane metod dla różnych atrybutów (np. „getFloat” dla atrybutów typu NUMERIC), należy jednak w takiej sytuacji zwrócić szczególną uwagę na to, by w wyniku zapytania nie zostały zwrócone wartości, które nie mieszczą się w zmiennych typu zwracanego przez metodę „getXXX”.

Każda z wyżej wymienionych metod przyjmuje jeden parametr pozwalający na określenie, którego atrybutu wartość należy pobrać. Możliwe jest albo podanie nazwy atrybutu w postaci łańcucha, albo numeru atrybutu w klauzuli SELECT liczonego od 1. Jeżeli podczas pobierania wartości atrybutu wystąpi błąd, zgłaszany jest wyjątek „SQLException”.

Należy tutaj zwrócić uwagę na jeszcze jedną rzecz. Niektóre z metod „getXXX” zwracają wartość 0 zamiast „null”, gdyż typ zwracanych przez nie wartości, nie przewiduje wartości „null”. Aby sprawdzić, czy ostatnia odczytana za pomocą metody „getXXX” wartość zawierała NULL, należy użyć bezparametrowej metody „wasNULL”, która zwraca wartość logiczną „true”, jeśli w atrybucie faktycznie znajdował się NULL, albo „false”, jeśli w atrybucie znajdowała się wartość 0.

Rozważmy przykład (3). Przykład ten zawiera pętlę „while”, w której warunkiem zakończenia jest przyjęcie przez omawianą wcześniej metodę „next” wartości „false”. Zgodnie z tym, co mówiono o metodzie „next” wcześniej, w kolejnych iteracjach pętli wskaźnik zapisany wewnątrz obiektu zapisanego w zmiennej „rs”, będzie wskazywał na kolejne krotki wyniku. Pętla zakończy się w momencie, kiedy zostaną odczytane wszystkie krotki. Rozważmy pierwszą instrukcję wewnątrz pętli:

String nazwisko=rs.getString("NAZWISKO");

Instrukcja rozpoczyna się od deklaracji zmiennej nazwisko typu „String”, do której przypisywany jest wynik działania metody „getString” aktywowanej na rzecz obiektu zapisanego zmiennej „rs”. Parametrem tej metody jest nazwa atrybutu relacji wynikowej zapytania. W tym przypadku jest to „NAZWISKO”. W wyniku działania metody „getString”, nazwisko z aktualnie wskazywanej krotki w wyniku zapytania jest zapisywane do zmiennej nazwisko. Druga instrukcja wewnątrz pętli ma analogiczną konstrukcję:

float placa=rs.getFloat(2);

Instrukcja rozpoczyna się od deklaracji zmiennej „placa” typu „float”, do której następnie przypisywany jest wynik działania metody „getFloat”. Parametrem tej metody jest numer atrybutu relacji wynikowej zapytania (podano tutaj 2, czyli atrybut PLACA_POD). W wyniku działania metody „getFloat”, płaca podstawowa z aktualnie wskazywanej krotki w wyniku zapytania jest zapisywana do zmiennej „placa”. W ostatnim wierszu pętli, na konsoli wypisywane są odczytane wyniki.

Po przeczytaniu wszystkich wyników, trzeba w sposób jawny zamknąć zbiór wyników za pomocą metody „close”. Jeżeli nie mamy zamiaru wykonywać kolejnych poleceń SQL, należy zamknąć za pomocą metody „close” również obiekt implementujący interfejs „Statement” (4). Aby wytłumaczyć konieczność jawnego zamykania zbioru wyników i obiektu pozwalającego na wysyłanie poleceń do SZBD, należy wprowadzić termin „kursor”. Kursorem nazywamy obszar pamięci operacyjnej na serwerze SZBD zawierający przetwarzany przez SZBD zbiór krotek (np. wyniki zapytania, krotki modyfikowane przez polecenia DML). Sposób dostępu do kursora zależy od języka programowania. W języku Java każdy obiekt implementujący interfejs ResultSet zapewnia interfejs pozwalający na odczytywanie wyników zwracanych przez kursor zapytania w SZBD. Kursor jest rezerwowany przez obiekt implementujący interfejs „Statement”, w momencie jego utworzenia. Zamknięcie tego obiektu za pomocą metody „close” zwalnia w SZBD zajęty przez niego kursor. Maksymalna liczba używanych równocześnie kursorów jest ograniczona. Jeżeli obiekty typu „Statement” nie będą zamykane, w krótkim czasie dojdzie do zajęcia wszystkich dostępnych kursorów, przez co nie będzie możliwe wykonywanie poleceń przez SZBD. W ogólności możliwe jest równoczesne wykonywanie wielu poleceń SQL, jednak dla każdego z tych poleceń należy utworzyć osobny obiekt implementujący interfejs „Statement”, gdyż na każdy obiekt „Statement” przypada jeden kursor, a zatem może na niego przypadać tylko jeden obiekt ResultSet.


Pełny kod programu, którego fragmenty przedstawiono na slajdzie, załączono do kursu w pliku JDBCELearning2.java.


<< Poprzedni slajd | Spis treści | Następny slajd >>