Struktury


Połączenie 

kwadrat   Klasa Connection odpowiada pojedynczemu połączeniu z wybranym Systemem Zarządzania Bazą Danych.
Po załadowaniu sterownika JDBC, użytkownik może połączyć się z bazą danych. Do tego celu służy metoda getConnection(...) z klasy DriverManager. W wyniku jej wywołania:

dostajemy obiekt klasy Connection. Parametrami metody są:

  • url - np: "jdbc:oracle:http://adres_hosta_z_baza_danych/nazwa_tabeli", czy też: "jdbc:mysql://localhost:3306/marek".
    Jest to tzw. JDBC URL, adres bazy danych (tabeli), postaci:
    jdbc:<subprotocol>:<subname>
    umożliwiający menedżerowi ustalić:
    1. typ protokołu - tutaj zawsze: "jdbc"
    2. do jakiej bazy danych się podłączamy: "oracle"
    3. gdzie znajduje się wybrana baza danych (tabela): "http://adres_hosta_z_bd/nazwa_tabeli"

  • username - identyfikator użytkownika bazy danych

  • password - hasło użytkownika bazy danych

Szczegóły dotyczące Java URL dostępne są w tutorialu JDBC.


Zapytania 

kwadrat   Klasa Statement reprezentuje medium, służące do transmisji wszelkich zleceń do bazy danych (operacji SQL).

Obiekt klasy Statement tworzony jest w oparciu o wsześniej ustanowione połączenie z bazą danych. Statement nie posiada samodzielnego konstruktora, nowy obiekt jest zwracany przez metodę createStatement():

Od tego momentu wszystkie operacje związane z bazą danych wykonuje się poprzez utworzony obiekt. Oczywiście można utworzyć więcej niż jeden obiekt klasy Statement. Co więcej, jest to jedyna metoda, by złożyć kolejne zapytanie podczas przeglądania wyników poprzedniego.

JDBC rozróżnia trzy odmienne kategorie zleceń do bazy danych. Kategorie te reprezentuje wspomniana klasa Statement i jej dwie podklasy: PreparedStatement oraz CallableStatement.

kwadrat   Statement

Do wykonywania operacji na bazie danych służą bezpośrednio trzy metody klasy: executeQuery(query), executeUpdate(query), execute(query), gdzie query jest treścią (String) zapytania. W szczególności:

  • executeQuery(query)
    używana jest do składania zwykłych zapytań SQL rozpoczynających się od słowa select. W wyniku wykonania metody otrzymujemy listę wierszy opakowaną w obiekt klasy ResultSet (nigdy nie otrzymamy null).


  • executeUpdate(query)
    używana jest do wykonywania operacji: insert, update i delete, a także operacji DDL (Data Definition Language): create table, drop table, czy też alter table.
    W wyniku zwraca pojedynczą liczbę, określającą liczbę wierszy tabeli, której dotyczyło zapytanie.


  • execute(query)
    używana jest rzadko, wszędzie tam, gdzie w wyniku otrzymujemy więcej niż jedną listę wierszy lub więcej niż jedną liczbę zmodyfikowanych wierszy

kwadrat   Wykonanie dowolnej operacji spośród powyższych powoduje zamknięcie otwartego (w trakcie analizy) obiektu ResultSet, o ile taki istnieje, związanego z używanym obiektem Statement. Pominięcie tego faktu, prowadzi do licznych błędów. Jeżeli w trakcie obróbki wyniku zapytania chcemy wykonywać kolejne operacje na bazie danych, należy utworzyć osobny obiekt Statement i z nim skojarzyć następne zapytanie.

W treści zapytania (zmienna query) mogą znajdować się dowolna, poprawna składniowo konstrukcja języka SQL.

kwadrat   ResultSet

Klasa ta reprezentuje podstawową strukturę danych wynikowych dla zapytań SQL. Intuicyjnie kojarzona z bazodanowym kursorem (iterator), udostępnia szereg metod pozwalających na przetwarzanie otrzymanych danych. Pojedynczy element iteratora odpowiada jednemu wierszowi wynikowej tabeli.

Obiekt klasy ResultSet otrzymujemy w wyniku wykonania metody: executeQuery(). Rodzina metod getXXX (i) służy do uzyskiwania wartości i-tej kolumny bieżącego wiersza wynikowej tabeli - np. getInt(1) oznacza pytanie o wartość całkowitą znajdującą się w pierwszej kolumnie aktualnego wiersza. Do następnego wiersza przesuwamy się korzystając z metody next(), uprzednio sprawdziwszy, czy w kursorze pozostały jeszcze wiersze (hasNext()).
Schemat analizy wyników zapytania przedstawia poniższy fragment programu:

Jeżeli pracujemy w trybie autocommit (transakcyjność), zapytanie zostaje zatwierdzone dopiero po pobraniu z kursora ostatniego wiersza lub po jego bezpośrednim zamknięciu (close()). Ma to oczywiście o wiele większe znaczenie w przypadku operacji insert/update/delete.

Jak widać, po wynikowej liście wierszy możemy poruszać się w jednym kierunku - do przodu. Wersja 2.0 standardu JDBC wprowadza rozszerzenie klasy ResultSet:

kwadrat   ScrollableResultSet

Klasa rozszerza funkcjonalność ResultSet o możliwość elastycznego poruszania się po otrzymanej liście wierszy oraz pozwala na modyfikacje tabeli w trakcie przeglądania wyników zapytania.

O rodzaju zwracanego obiektu, a więc wyborze pomiędzy klasą ResultSet a ScrollableResultSet decyduje metoda tworząca kontener Statement. Użycie bezparametrowego wywołania createStatement () jest rozwiązaniem standardowym. Natomiast zastosowanie createStatement (int jaki_rezultat, int jaka_wspolbieznosc) tworzy kontener zdolny do tworzenia elastycznych wyników.
Pierwszy argument decyduje o możliwości dwukierunkowego przewijania kursora oraz reakcji na zmiany dokonane w bazie danych po pobraniu danych. Dopuszczalne są trzy stałe:

  • TYPE_FORWARD_ONLY
    Klasyczne rozwiązanie, brak możliwości cofania kursora

  • TYPE_SCROLL_INSENSITIVE
    Po kursorze możemy się dowolnie poruszać, włącznie z przemieszczaniem do dowolnego wiersza. Zmiany zaistniałe w bazie danych po wykonaniu zapytania nie wpływają na zawartość kursora.

  • TYPE_SCROLL_SENSITIVE
    Najbardziej elastyczne rozwiązanie. Poruszamy się jak w poprzednim przypadku, dodatkowo zmiany w bazie danych są odnotowywane przez kursor.

Drugi argument metody określa poziom współbieżności. Możliwe są dwie stałe:

  • CONCUR_READ_ONLY
    Rozwiązanie klasyczne - działa w parze z opcją TYPE_FORWARD_ONLY

  • CONCUR_UPDATABLE
    Pozwala użytkownikowi na wykonywanie tzw. programowych operacji zapisu/modyfikacji/usunięcia danych znajdujących się bezpośrednio w bazie danych. Jest to istotne rozszerzenie w stosunku do wersji 1.0 JDBC. Pozwala m.in. na obudowywanie kursorów warstwą prezentacyjną (formatka).
    Do programowych modyfikacji odpowiednich kolumn bazy danych służą metody postaci updateXXX (pozycja, wartosc) oraz insertRow () i deleteRow ().

kwadrat   PreparedStatement

Dla usprawnienia procesu przesyłania danych wprowadzono mechanizm wstępnego przetwarzania zapytań. Zapytanie, po przesyłaniu do bazy danych, jest prekompilowane i od tego momentu użytkownik nie musi go przesyłać po raz kolejny. Oczywiście zastosowania tego mechanizmu ograniczają się do wąskiego zakresu przypadków:

  • treść zapytania nie zmienia się w czasie - zapytanie jest wielokrotnie ponawiane (procedura bezparametrowa)
  • zapytanie jest przetwarzane bardzo często, jego treść można rozsądnie sparametryzować

W obu przypadkach warto rozważyć użycie osadzonych w SZBD, prekompilowanych zapytań.

Parametry wejściowe procedur (IN) zapisujemy zgodnie z regułami sekwencji rozszerzających i kodujemy jako znaki zapytania ("?"). Ustawienie odpowiednich wartości dla brakujących argumentów odbywa się poprzez metody z rodziny setXXX (pozycja, wartosc), gdzie pozycja jest kolejnym (licząc od lewej, począwszy od 1) argumentem zapytania.
Przykładowo:


Procedury 

kwadrat   Sekwencje rozszerzające

JDBC umożliwia korzystanie z funkcji skalarnych wbudowanych w SZBD. Sterowniki spełniające warunki zgodności z JDBC (JDBC Compliant) muszą zapewniać poprawność działania z funkcjami skalarnymi, o ile odpowiadający im SZBD funkcje te udostępnia.
Z uwagi na różnorodność wywołań funkcji u różnych producentów baz danych, JDBC wprowadziło tzw. sekwencje rozszerzające (escape sequences) - składniowe ramy dla wywołań funkcji i procedur składowanych, przekazywania daty, czasu itp. W szczególności, wywołanie funkcji opatrzone jest następującą klauzulą:

np.

Sekwencje rozszerzające określają także sposób wołania i przekazywania paramerów dla procedur składowanych.

kwadrat   Procedury składowane

Poza funkcjami skalarnymi, JDBC umożliwia wykorzystanie procedur składowanych (stored procedures) - procedur i funkcji zgromadzonych po stronie SZBD. Wołanie procedur oraz przekazywanie parametrów (w obu kierunkach) określają reguły składniowe sekwencji rozszerzających. Nośnikiem dla zapytań zawierających wywołania procedur są obiekty klasy CallableStatement, stanowiącej rozszerzenie klasy Statement. Po utworzeniu obiektu wspomnianej klasy należy przygotować treść zapytania:

Znaki zapytania odpowiadają zmiennym przekazywanym procedurze. JDBC dopuszcza zmienne trzech typów (koncepcyjnych):

  • IN
    Wartości zmiennych przekazywane są procedurze. Do ustawiania argumentu typu IN stosujemy metody postaci setXXX (pozycja, wartosc), gdzie pozycja, określa do którego znaku "?" przyporządkowana będzie wartosc

  • OUT
    Z argumentem wiążemy zmienną programu - po wykonaniu procedury zmienna będzie miała odpowiednio zmodyfikowaną wartość. Do związania zmiennej używa się polecenia: registerOutParameter (pozycja, typ), gdzie pozycja jest określona jak dla argumentu typu IN, a typ odpowiada jednemu z typów JDBC.

  • INOUT
    Argument spełnia obie powyższe role. Dla argumentu określonego jako INOUT musi określić wysyłaną wartość (setXXX (p, w)), jak i związać z nim zmienną Javy (registerOutParameter (p, t))

Dla powyższego przykładu wykonujemy następujący ciąg poleceń:


Operacje Grupowe 

kwadrat   Wersja 2.0 JDBC wprowadza pojęcie operacji grupowych (batch updates). Umożliwiają one zestawienie wielu zapytań do bazy danych i wykonanie ich jednorazowo. Poszczególne sterowniki JDBC nie muszą wspierać tego rozwiązania, ani zapewniać istotnej poprawy wydajności. Sprawdzenie, czy dany sterownik implementuje operacje grupowe odbywa się poprzez wywołanie metody:

Zarządzanie zapytaniami wchodzącymi w skład operacji grupowej odbywa się poprzez zestaw metod klasy Statement:

  • addBatch("tresc_zapytania")
    dodanie cząstkowego zapytania
  • clearBatch()
    usunięcie wszystkich zapytań wchodzących w skład jednej grupy
  • executeBatch()
    wykonanie zbiorowego zapytania - w wyniku otrzymujemy tablicę liczb całkowitych, które odpowiadają kodom wykonania każdego cząstkowego zapytania

Wystąpienie błędu podczas wykonania cząstkowego zapytania powoduje podniesienie wyjątku BatchUpdateException(). Jego obsługa wiąże się m.in. z analizą wynikowej tablicy kodów, dostępnej poprzez wywołanie metody getUpdateCounts().



 powrót | początek | poprzedni | następny   Marek Misiowiec