JDBC

34
JDBC Agenda: Wprowadzenie JDBC VS ODBC Fundament innego API Zgodność z SQL Sterowniki (rodzaje) Użycie Wersje Połączenie Zapytania Procedury Transakcje Przykłady

description

JDBC. Agenda: Wprowadzenie JDBC VS ODBC Fundament innego API Zgodność z SQL Sterowniki (rodzaje) Użycie Wersje Połączenie Zapytania Procedury Transakcje Przykłady. Wprowadzenie. - PowerPoint PPT Presentation

Transcript of JDBC

Page 1: JDBC

JDBCAgenda:

WprowadzenieJDBC VS ODBCFundament innego APIZgodność z SQLSterowniki (rodzaje)UżycieWersjePołączenieZapytaniaProceduryTransakcjePrzykłady

Page 2: JDBC

  Wprowadzenie  Java DataBase Connectivity (JDBC) jest interfejsem

programistycznym, skonstruowanym w i przeznaczonym dla języka Java, który umożliwia ustandaryzowany dostęp do większości obecnych na rynku systemów bazodanowych. Wraz z powstaniem nowego, przenośnego, niezależnego od platformy i architektury języka programowania pojawiła się idea skonstruowania nowego interfejsu bazodanowego, który spełniałby podobne wymagania jak sam język. Naturalną konsekwencją takiego rozumowania było oderwanie się od już istniejących API, w szczególności wprowadzonego przez Microsoft standardu Open DataBase Connectivity (ODBC), i opracowanie nowej technologii, wykonanej w pełni w Javie. Jakkolwiek nie oznacza to, że programiści używający dotąd ODBC musieli przestawić się na zupełnie nowy tok myślenia. Przeciwnie, JDBC funkcjonalnie przypominało technologię ODBC, zwiększono jedynie możliwości interfejsu oraz przystosowano go do odmiennej specyfiki języka Java.

Page 3: JDBC

JDBC VS ODBCStworzenie nowego standardu dostępu do systemów

zarządzania bazami danych (SZBD) w przeciwieństwie do zaadoptowania ODBC na potrzeby Javy wynikało między innymi z następujących spostrzeżeń: ODBC było technologią stworzoną i stosowaną w środowiskach powstałych w oparciu o języki C i C++. Aplikacje tworzone z ich użyciem są zależne od systemu operacyjnego, co kłóci się z jednym z fundamentów języka Java - przenośnością oprogramowania.Przepisanie ODBC w Javie nie miało sensu, z uwagi na różnice językowe (konstrukcyjne) pomiędzy Javą a C.ODBC, w oczach twórców Javy, było zbyt skomplikowane. Nowo powstały interfejs miał być znacznie prostszy w użyciu, a jednocześnie bardziej funkcjonalny.

Page 4: JDBC

Fundament innego APIJDBC jest wykorzystywane nie tylko bezpośrednio, jako

zunifikowana technologia dostępu do dowolnej bazy danych, ale także jako budulec dla aplikacji/interfejsów wyższego rzędu, które umożliwiają dostęp do bazy danych z wyższego poziomu.

Przykładami takich przedsięwzięć są m.in:

SQLJ - SQL zaszyty w kodzie Javy. Kod ten jest następnie preprocesowany, tak by wydobyć zeń właściwe komendy SQL, za wykonanie których odpowiada JDBC.

Page 5: JDBC

Zgodność z SQLJDBC określa pewien poziom zgodności z dotychczasowymi

standardami SQL. Główne założenie mówi, iż każdy sterownik JDBC musi odpowiadać co najmniej wersji ANSI SQL-92 standardu SQL. Ponadto pomysłodawcy interfejsu poczynili inne założenia, które spełniają kolejne wersje standardu JDBC:

Zapytania SQL przesyłane są do odpowiedniego SZBD bez względu na możliwość ich realizacji. W przypadku, gdy dany SZBD nie potrafi obsłużyć zlecenia przekazanego przez JDBC, aplikacja podnosi określony wyjątek.

JDBC udostępnia informacje o SZBD i jego cechach szczególnych (ustawieniach, możliwościach itd.). Informacje te przekazywane są

użytkownikowi w postaci tzw. metadanych.

Page 6: JDBC

SterownikiSterownik JDBC jest zbiorem skompilowanych klas, które

implementują wszystkie interfejsy zawarte w java.sql oraz przedefiniowują (ponownie implementują) pozostające tam klasy. Implementacja bezpośrednio zależy od systemu zarządzania bazą danych, z którą będzie się łączyć aplikacja wykorzystująca sterownik. Stąd każdy sterownik JDBC służy do komunikacji z konkretną bazą danych i nie jest wykorzystywany w przypadku baz innych producentów.

Zastosowane rozwiązanie, choć podobne do technologii używanych w przypadku C++ lub innych języków, w przypadku Javy nabiera szerszego znaczenia. Ponieważ Java jest językiem w pełni przenośnym, producenci sterowników muszą przygotowywać tylko jeden pakiet dla każdej wersji standardu JDBC. Tym samym, w odróżnieniu np. od wspomnianych interfejsów dla języka C++, z jednego binarium korzystamy w systemie Linux i w Windows.

Page 7: JDBC

Rodzaje sterownikówPonieważ nie wszyscy producenci systemów

bazodanowych przygotowali javowe implementacje standardu JDBC, a niektórzy przygotowali rozwiązania hybrydowe, przyjęło się rozróżniać cztery zasadnicze typy sterowników JDBC:

1. Mosty JDBC-ODBC (JDBC-ODBC bridge) - korzystamy ze sterownika ODBC, z którym komunikuje się nasz most. Zapytania formułowane w Javie są tłumaczone na język sterownika ODBC. Wszelka komunikacja z bazą danych odbywa się poprzez sterownik ODBC.

2. Java do API SZBD (Native-API partly-Java) - sterowniki wykorzystują biblioteki napisane w C/C++. Ich używanie jak w przypadku powyżej wymaga dodatkowego oprogramowania.

Page 8: JDBC

Rodzaje sterowników cd.3. Pośrednie JDBC (JDBC-Net pure Java) -

sterownik JDBC komunikuje się z serwerem pośredniczącym, za pomocą protokołu niezależnego od SZBD. Serwer tłumaczy polecenia na protokól konkretnego SZBD i przesyła do niego otrzymane zapytania. Serwer może pośredniczyć w wymianie danych pomiędzy wieloma klientami i wieloma różnymi SZBD. Tym samym jest to najbardziej ogólne i heterogeniczne rozwiązanie, obciążone względami bezpieczeństwa.

4. Bezpośrednie JDBC (Native-protocol pure Java) - sterownik JDBC komunikuje się bezpośrednio z bazą danych przy pomocy jej protokołu sieciowego. Rozwiązanie najbardziej ogólne, z powodzeniem stosowane w sieciach wewnętrznych.

Page 9: JDBC

Sterowniki cd.Poniższy rysunek obrazuje wspomniane rozwiązania ujęte w

modelu warstwowym:

Page 10: JDBC

UżyciePrzed skorzystaniem z klas java.sql, należy pobrać odpowiedni

pakiet zawierający dany sterownik JDBC, a następnie umieścić go (zgodnie z hierarchią katalogów zawartą w archiwum) w katalogu widocznym dla maszyny wirtualnej Javy (zmienna CLASSPATH). Po wykonaniu tych operacji sterownik JDBC jest gotów do pracy. Każda aplikacja może go dynamicznie załadować. Do tego celu służy polecenie:

Class.forName("pełna_nazwa_sterownika") gdzie, w przypadku bazy Oracle, pełna_nazwa_sterownika, to

oracle.jdbc.driver.OracleDriver.Sterownik w pełni zgodny ze standardem JDBC, powinien wtedy stworzyć także instancje klasy. Ponieważ nie wszystkie sterowniki spełniają ten wymóg, warto samodzielnie powołać do życia obiekt klasy:

Class.forName("oracle.jdbc.driver.OracleDriver").newInstance()Inną metodą na załadowanie sterownika jest ustalenie własności jdbc.drivers na nazwę

ładowanej klasy: java -Djdbc.drivers="oracle.jdbc.driver.OracleDriver" program

Page 11: JDBC

Wersje JDBCJDBC 1.0     Pierwsza wersja standardu JDBC. Pojawiła się na rynku wraz

z wypuszczeniem JDK 1.0 (Java Development Kit). Zawierała podstawowy zestaw narzędzi umożliwiających dostęp do bazy danych. W pakiecie java.sql znalazły się następujące interfejsy:

ConnectionDatabaseMetaDataDriverDriverManagerResultSetResultSetMetaDataStatement

CallableStatementPreparedStatement

Types

Page 12: JDBC

Wersja JDBC Standard JDBC 2.0 pojawił się wraz z Java SDK 1.2.

Stanowi on funkcjonalne rozwinięcie wersji pierwszej, tak by sprostać wymaganiom stawianym przez pozostałe produkty Suna. Jego powstanie było w szczególności związane z wprowadzeniem przez Suna nowych technologii: Java Transaction Service (JTS), Java Naming and Directory Interface (JNDI), JavaBeans, czy też Enterprise JavaBeans (EJB). Do opublikowania nowej wersji JDBC przyczynił się także rozwój obsługi standardów wielojęzycznych.

JDBC 2.0 podzielony jest na dwie części:

JDBC 2.0 core API - zawarta w java.sql - posiada pełny zestaw mechanizmów dostępu do baz danych. Faktycznie składa się z części JDBC 1.2 uzupełnionej o szereg nowych funkcji.

Page 13: JDBC

PołączenieKlasa 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:

Connection con =     DriverManager.getConnection (url, username, password)

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/bazka".

username - identyfikator użytkownika bazy danych

password - hasło użytkownika bazy danych

Page 14: JDBC

ZapytaniaKlasa 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():  Connection con = DriverManager.getConnection (...)Statement stmt = con.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

Page 15: JDBC

Zapytania cd.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. 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

Page 16: JDBC

Zapytania - ResultSetKlasa 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()).

Page 17: JDBC

ScrollableResultSetKlasa 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ą stałe: TYPE_FORWARD_ONLY Klasyczne rozwiązanie, brak możliwości cofania kursoraTYPE_SCROLL_INSENSITIVEPo 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)

Page 18: JDBC

ScrollableResultSetDrugi argument metody określa poziom współbieżności. Możliwe są dwie

stałe: CONCUR_READ_ONLYRozwiązanie klasyczne - działa w parze z opcją TYPE_FORWARD_ONLYCONCUR_UPDATABLEPozwala 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 ().

Page 19: JDBC

PrepareStatementDla 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 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.

Page 20: JDBC

PrepareStatement - przykład

pstmt = con.prepareStatement (   "update nazwa_tabeli set kol_1 = ? and kol_2 = ?     where jakas_wartosc = ?");pstmt.setString (1, "cos"); pstmt.setInt (2, 123); pstmt.setInt (3, 8395);  pstmt.executeUpdate ();

Page 21: JDBC

ProceduryJDBC 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ą:

{fn <nazwa_funkcji ()>}np. Select {fn concat (string, "napis")}

From...

Page 22: JDBC

Procedury składowanePoza 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 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:

 

 

? = call nazwa_procedury ( ? ? )

Page 23: JDBC

Procedury składowane cd.? = call nazwa_procedury ( ? ? )

Znaki zapytania odpowiadają zmiennym przekazywanym procedurze. JDBC dopuszcza zmienne trzech typów: 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 wartoscOUT 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))

Page 24: JDBC

Procedury składowe - przykładCallableStatement cs =

    con.prepareCall (" {? = call nazwa_procedury (? ?)} "); cs.registerParameterOut (1, Types.INTEGER);cs.setString (2, "arg_napisowy");cs.setString (3, "2_arg_napisowy");cs.registerParameterOut (3, Types.STRING); cs.execute (); int wynik = cs.getInt (1);String arg_2 = cs.getString (3);

Page 25: JDBC

TransakcjeJDBC domyślnie ogranicza pojęcie transakcji do pojedynczej

operacji. Jej pomyślne wykonanie oznacza zatwierdzenie efektów operacji - jest to tzw. tryb autocommit. Dokładniej, efekty operacji zostają zatwierdzone dopiero po pobraniu ostatniego wiersza wynikowego kursora (ResultSet) lub po jego zamknięciu.Aby posłużyć się rozszerzonym pojęciem transakcji, należy wyłączyć tryb samozatwierdzania, wywołując metodę klasy Connection:

con.setAutoCommit(false); Zatwierdzenie ciągu operacji wykonanych od ostatniego zatwierdzania

transakcji odbywa sie poprzez wywołanie metody: Connection.commit();Transakcje wycofujemy wywołaniem: Connection.rollback();

Page 26: JDBC

PrzykładStatement stm =

con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);

String sql = „select * from tabela”;

ResultSet rs = stm.executeQuery(sql);

rs.afterLast();

while(rs.previous()){

System.out.println(„Wiek” + rs.getInt(„wiek”));

Page 27: JDBC

PrzykładWybrane medody obiektu ResultSet:

rs.Next();

rs.previous();

rs.afterLast();

rs.beforeFirst();

rs.getXXX(); //numer argumentu zapytanie lub nazwa kolumny

rs.absolute(int a);

rs.relative(int a);

rs.first();

rs.last();

rs.updateXXX(„nazwa_kol”,wartosc);

rs.updateRow(); rs.insertRow();

rs.deleteRow(); rs.refreshRow();

Page 28: JDBC

PrzykładAktualizacja za pomocą obiektu ResultSet:

String sql = „Select * from osoba”;

ResultSet rs = stm.executeQuery(sql);

rs.first();

String nazwisko = rs.getString(„Nazwisko”);

rs.updateString(„Nazwisko”, „Pan” + nazwisko);

rs.updateInt(„Wiek”, 22);

rs.updateRow();

Usuwanie za pomocą obiektu ResultSet:

rs.absolute(4);

rs.deleteRow();

Page 29: JDBC

PrzykładWstawianie rekordu za pomocą ResultSet:

String sql = „select * from osoba”;

ResultSet rs = stm.executeQuery(sql);

Rs.moveToInsertRow();

rs.updateInt(„Wiek”, 34);

rs.updateString(„Programista Java”);

rs.insetRow();

Odświerzanie danych za pomocą obiektu ResultSet:

rs.absolute(5);

rs.refreshRow();

Modyfikacja a bezpieczeństowo transakcji:

String sql = „Select from osoba FOR UPDATE”;

Page 30: JDBC

PrzykładBatch update:

con.setAutoCommit(false);

try{

Statement stm = con.createStatement();

stm.addBatch(insert into osoba(imie,nazwisko) values(„Jan”,Kowalski”);

stm.addBatch(delete from osoba where nazwisko=‘Nowak’”);

stm.addBatch(update osoba set imie=„Witold” where nazwisko=‘Kowalski’”);

stm.executeBatch(); //stm.clearBatch();

}catch(BatchUpdateException e){int[] count = e.getUpdateCounts();

}

Page 31: JDBC

PrzykładMetadane:

Statement stm = con.createStatement();

String sql = „select * from osoba”:

ResultSet rs = stm.executeQuery(sql);

ResultSetMetaData meta = rs.getMetaData();

int col = meta.getColumnCount();

for(int i = 0;i < col;i++){

System.out.println(meta.getColumnLabel()):

}

Page 32: JDBC

PrzykładStruktury:public class DaneOsoboweObj implements SQLData{

private String sql_type;

int waga;

int wiek;

DaneOsobowe(){}

DaneOsobowe(String sql_type, int waga, int wiek){

this.sql_type = sql_type; this.waga = waga; this.wiek=wiek; }

public String getSQLTypeName() throws SQLException{

return sql_type; }

public void readSQL(SQLInput stream, String typeName) thows SQLException{

sql_type = typeName; waga = stream.getInt(); wiek = stream.getInt(); }

public void writeSQL(SQLOutput stream) throws SQLException{

stream.writeInt(waga);

stream.writeInt(wiek); }

CREATE TYPE OsobaProp(

waga Number,

Wiek Numer);

Page 33: JDBC

Przykład struktury cd.Map map = con.getTypeMap();

map.put(„OsobaProp”,Class.forName(„DaneOsoboweObj”));

Statement stm = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,

ResultSet.CONCUR_READ_ONLY);

ResultSet rs = stm.executeQuery(„select Dane from Osoba where nazwisko = ‘Nowak’”);

rs.absolute(1);

DaneOsoboweObj daneOs = (DaneOsoboweObj)rs.getObject(„Dane”);

System.out.println(„Nazwisko” + daneOs.nazwisko);

Aktualizacja:

daneOs = new DaneOsoboweObj(„Adam”, „Mickiewicz”);

rs.exectueQuery(„Update Osoba set Dane = daneOs where nazwiko=„Nowak”);

stm.execute();

Page 34: JDBC

KONIEC