java_bazy_danych.pdf

(177 KB) Pobierz
Microsoft Word - roz_9.doc
Jacek Rumi ń ski - J ę zyk JAVA – Rozdzia ł 9
Rozdział 9 Obsługa baz danych w języku Java
9. 1 Obs ł uga baz danych w Javie - pakiet SQL
9.2 Utworzenie po łą czenia z baz ą danych
9.3 Sterowniki
9.4 Wys ł anie polecenia SQL
9.5 Rezultaty i ich przetwarzanie
9.1 Obsługa baz danych w Javie - pakiet SQL
Ze względu na tak dużą popularność baz danych oraz z uwagi na liczne
mechanizmy pracy z bazami danych jakie dostarcza język Java warto omówić
podstawy bibliteki Java JDBC API. JDBC jest znakiem towarowym firmy SUN (nie
jest to skrót, często tłumaczony jako Java Database Connectivity) określającym
interfejs języka Java przeznaczony do wykonywania poleceń SQL (Structured Query
Language). Strukturalny język zapytań SQL jest uniwersalnym, znormalizowanym
(Java obsługuje SQL zgodnie z normą ANSI/ISO/IEC 9075:1992, inaczej SQL-2)
językiem pracy z bazami danych. W oparciu o SQL tworzone są systemy
zarządzania bazami danych (DBMS - DataBase Management System), których rolą
jest m.in tworzenie struktury bazy, wypełnianie bazy danych, usuwanie lub
aktualizacja rekordów, nadawanie praw dostępu, itp. JDBC jest interfejsem niskiego
poziomu wywołującym bezpośrednio polecenia języka SQL. Rolę JDBC można więc
ująć w trzech punktach:
1. utworzenie połączenia z bazą danych,
2. wysłanie polecenia (poleceń) SQL,
3. przetworzenie otrzymanych wyników.
JDBC może stanowić podstawę do tworzenia interfejsów wyższego rzędu. Znane są
prace nad stworzeniem interfejsu mieszającego elementy SQL i Javy (np.
umieszczenie zmiennych Javy w SQL). Określony preprocesor wbudowanego w
Javie języka SQL tłumaczyłby stworzone rozkazy na rozkazy niskiego poziomu
zgodnie z JDBC. Inna wersja interfejsu wysokiego rzędu zakłada odwzorowanie tabel
na klasy. Każdy rekord staje się wówczas obiektem danej klasy. Tworzenie
interfejsów wyższego poziomu jest również istotne z punktu widzenia planowanego
modelu dostępu do bazy danych. Popularna dwu-warstwowa metoda dostępu (two-
tier) daje bezpośredni dostęp do bazy danych (aplikacja/applet - baza danych) .
Oznacza to, że musimy znać format danych bazy by móc pobrać lub zmienić
informacje. W przypadku bardziej uniwersalnym dodaje się trzecią warstwę w modelu
dostępu do bazy (aplikacja/applet (GUI) - serwer - baza danych). W modelu trzy
punktowym stosuje się interfejs wyższego poziomu po to aby struktura dostępu do
bazy danych stanowiła pewną abstrakcję, co umożliwia tworzenie różnych klientów
bez potrzeby zagłębiania się w szczegóły protokołów wymiany danych z bazą. Tak
stworzona konstrukcja dostępu do bazy danych uwalnia klienta od znajomości
organizacji bazy danych, co za tym idzie możliwe są prawie dowolne modyfikacje
ustawień bazy danych np. kilka rozproszonych baz zamiast jednej.
Istnieją inne interfejsy dostępu do baz danych jak na przykład popularny Open
DataBase Connectivity firmy Microsoft. Jednak korzystanie z ODBC przez programy
Javy nie stanowi dobrego rozwiązania ponieważ:
9-3
Jacek Rumi ń ski - J ę zyk JAVA –
Jacek Rumi ń ski - J ę zyk JAVA – Rozdzia ł 9
1. występuje różnica języków programowania - ODBC jest stworzony w C, a co za
tym idzie konieczna konwersja porzuca cechy języka Java, a często staje się nie
realizowalna ze względu na inne koncepcje np. problem wskaźników
2. korzystanie z ODBC jest znacznie trudniejsze, a nauka pochłania zbyt dużo
czasu,
3. praca z ODBC wymaga ręcznych ustawień na wszystkich platformach klientów,
podczas gdy korzystanie z JDBC umożliwia automatyczne wykorzystanie kodu JDBC
na wszystkich platformach Javy począwszy od komputerów sieciowych do
superkomputerów.
W okresie wprowadzania języka Java oraz sterowników JDBC stworzono (JavaSoft)
mosty JDBC-ODBC, będące rozwiązaniem dla tych, którzy korzystają z baz danych
nie posiadających innych, "czystych" sterowników JDBC.
9.2 Utworzenie połączenia z bazą danych
Stworzenie połączenia z bazą danych polega utworzeniu obiektu Connection.
W tym celu stosuje się jedną ze statycznych metod DriverManager.getConnection().
Każda metoda getConnection() zawiera jako argument adres URL dostępu do bazy
danych. Adres ten definiowany jest poprzez trzy człony:
d
b
c
:
<
s
u
b
p
r
o
t
o
c
o l l
>
:
<
s
u
b
n
a
m
e
>
.
Pierwszy element adresu jest stały i nosi nazwę jdbc. Określa on typ protokołu.
Kolejny element stanowi nazwa sterownika lub mechanizmu połączenia do bazy
danych. Przykładowo mogą to być nazwy: msql - sterownik dla bazy mSQL, odbc -
mechanizm dla sterowników typu ODBC. Ostatna część adresu zawiera opis
konieczny do zlokalizowania bazy danych. Element ten zależy od sterownika czy
mechanizmu połączeń i może zawierać dodatkowe rozszerzenia zgodnie z koncepcją
przyjętą przez twórcę sterownika. Standardowo omawiana część adresu wygląda
następująco:
/
/
h
o
s
t
n
a
m
e
:
p
o
r
t
/
s
u
b
s
u
b
n
a
m
e
.
Przykładowe pełne adresy url mogą wyglądać następująco:
j j
d
b
c
:
o
d
b
c
:
b i i
o
m
e
d
,
j j
d
b
c
:
m
s
q l l
:
/
/
a
t
h
e
n
s
. i i
m
a
g i i
n
a
r
y
.
c
o
m
:
4
3
3
3
/
d
b
_
t
e
s
t
.
Jedna z metod getConnection() umożliwia dodatkowo przesłanie nazwy użytkownika
i hasła dostępu do bazy danych:
g
e
t
C
o
n
n
e
c
t i i
o
n
(
S
t
r i i
n
g
u
r l l
,
S
t
r i i
n
g
u
s
e
r
,
S
t
r i i
n
g
p
a
s
s
w
o
r
d
)
.
Połączenie byłoby niemożliwe bez istnienia sterowników. Zarządzaniem
sterownikami, które zarejestrowały się za pomocą metody
DriverManager.registerDriver() zajmuje się klasa DriverManager (np. metody
getDriver(), getDrivers()). Klasy sterowników powinny zawierać kod statyczny (static
{}), który w wyniku ładowania tych klas stwarza obiekt danej klasy automatycznie
rejestrującej się za pomocą metody DriverManager.registerDriver(). Ładowanie
sterownika (a więc jego rejestracja) odbywa się najczęściej poprzez wykorzystanie
9-4
Jacek Rumi ń ski - J ę zyk JAVA –
j j
Jacek Rumi ń ski - J ę zyk JAVA – Rozdzia ł 9
metody Class.forName(). Ta metoda ładowania sterownika nie zależy od ustawień
zewnętrznych (konfiguracji sterowników) i ma charakter dynamiczny. Przykładowe
ładowanie sterownika o nazwie "oracle.db.Driver" wykonane jest poprzez
zastosowanie metody Class.forName("oracle.db.Driver"). Fragment kodu obrazujący
etap łączenia się z bazą danych ukazano poniżej:
String url = "jdbc:odbc:kurs";
// przykładowa nazwa drivera - slowo "kurs" jest nazwą zasobów
//definiowaną w ODBC dla bazy np. pliku tekstowego
String username = ""; //brak parametrów dostępu do pliku tekstowego
String password = "";
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
//ładowanie sterownika - most JDBC-ODBC
} catch (Exception e) {
System.out.println("Blad ladowania sterownika JDBC/ODBC.");
return;
}
Connection c = null;
try {
c = DriverManager.getConnection (url, username, password); //połączenie
} catch (Exception e) {
System.err.println("Wystapil problem z polaczeniem do "+url);
}
Powyższy przykład zakłada rejestrację w ODBC bazy tekstowej o dostępie "kurs" i
wskazanie odpowiedniego katalogu.
9.3 Sterowniki
Sterowniki, a więc pakiety kodu zawierającego implementację deklarowanych
klas i metod (obsługa dostępu do bazy, np. implementacja metod interfejsu ResultSet
jak first() getInt(); itp.) są zazwyczaj dzielone na cztery grupy:
a. sterowniki JDBC odwzorowujące żądaną funkcjonalność na funkcjonalność
sterowników Open Database Connectivity – ODBC. Sterowniki te oznaczanę są
często jako mosty JDBC-ODBC. Sun standardowo dostarcza swoją wersję
mostu.
b. Sterowniki JDBC odwzorowujące żądaną funkcjonalność na funkcjonalność
dostępną poprzez sterowniki binarne danej bazy danych.
c. Sterowniki JDBC odwzorowujące żądaną funkcjonalność na funkcjonalność
oprogramowania pośredniczącego w komunikacji z serwerem bazy danych, czyli
z następuje tłumaczenie poleceń.
d. Sterowniki JDBC odwzorowujące żądaną funkcjonalność na funkcjonalność
serwera bazy danych. Jest to w pełni zgodne z Javą rozwiązanie, które zapewnia
najczęściej twórca oprogramowania serwera bazy danych.
Poniższy fragment kodu demonstruje zasady tworzenia połączenia i wykorzystywania
kodu zdalnego (sterowniki) dla bazy danych „qabase” pracującej na serwerze Msql:
try{
9-5
Jacek Rumi ń ski - J ę zyk JAVA –
Jacek Rumi ń ski - J ę zyk JAVA – Rozdzia ł 9
}
String URL = "jdbc:msql://biomed.eti.pg.gda.pl:1114/qabase";
String username ="msql";
String password="";
s=null;
con=null;
try{
con=DriverManager.getConnection(URL,username,password);
s=con.createStatement();
}catch (Exception e) {
System.err.println("Błąd połączenia z "+URL);
}
W przypadku apletu sterowniki (pakiet kodu) musi być zainstalowany na serwerze
WWW tam, skąd pochodzi aplet.
9.4 Wysłanie polecenia SQL
W celu wysłania polecenia SQL należy stworzyć obiekt Statement. Obiekt ten
stanowi kontener dla wykonywanych poleceń SQL. Wykorzystywane są dodatkowo
dwa kontenery: PreparedStatement oraz CallableStatement. Obiekt Statement jest
wykorzystywany do wysyłania prostych poleceń SQL nie zawierających parametrów,
obiekt PreparedStatement używany jest do wykonywania prekompilowanych
(przygotowanych - prepared) poleceń SQL zawierających jedno lub więcej pól
parametrów (oznaczanych znakiem "?"; tzw. parametry IN), natomiast obiekt
CallableStatement jest wykorzystywany do stworzenia odwołania (call) do
przechowywanych w bazie danych procedur. W celu stworzenia obiektu dla
opisanych wyżej interfejsów wykorzystuje się trzy odpowiednie metody interfejsu
Connection: createStatement() - dla interfejsu Statement, prepareStatement() - dla
interfejsu PreparedStatement oraz prepareCall() dla interfejsu CallableStatement.
Przykładowo fragment kodu tworzący obiekt wyrażenia Statement może wyglądać
następująco:
Connect i ion c = nu l l l l;
try {
c = Dr i iverManager.getConnect i ion (ur l l, username, password); //po ł ł ł ą ączen i ie
Statement s = c.createStatement(); // tworzymy ob i iekt wyra ż żen i ia
} catch (Except i ion e) {
System.err.pr i int l ln("W ystap i i l l prob l lem z po l laczen i iem do "+ur l l);
}
Posiadając obiekt Statement można wykorzystać trzy podstawowe metody
umożliwiające wykonanie polecenia SQL. Pierwsza z metod executeQuery() jest
używana do wykonywania poleceń, których efekt daje pojedynczy zbiór rezultatów
ResultSet np. wyrażenie SELECT - wybierz. Drugą metodę executeUpdate()
wykorzystuje się przy wykonywaniu poleceń INSERT, UPDATE oraz DELETE a
9-6
Jacek Rumi ń ski - J ę zyk JAVA –
Class.forName("com.imaginary.sql.msql.MsqlDriver");
}catch (Exception e){
System.out.println("Błąd wczytywania sterowników");
return;
Jacek Rumi ń ski - J ę zyk JAVA – Rozdzia ł 9
także wyrażeń typu SQL DDL (Data Definition Language - język definicji danych) jak
CREATE TABLE i DROP TABLE. Efekt działania pierwszych trzech poleceń daje
modyfikację jednej lub więcej kolumn w zero i więcej wierszach tabeli. Zwracana
wartość w wyniku działania metody executeUpdate() to liczba całkowita wskazująca
ilość rzędów, które podlegały modyfikacjom. Dla wyrażeń SQL DDL zwracana
wartość jest zawsze zero. Metoda execute() jest rzadko używana, ponieważ jest
przygotowana do obsługi poleceń zwracających więcej niż jeden zbiór danych (więcej
niż jeden obiekt ResultSet). Obsługa zwracanych danych jest więc kłopotliwa stąd
metoda ta jest wykorzystywana dla obsługi specjalnych operacji. W przypadku
obiektu PreparedStatement interfejs definiuje własne metody execute(),
executeUpdate() oraz executeQuery(). Dlaczego? Czy nie wystarczy, że interfejs
PreparedStatement dziedziczy wszystkie metody interfejsu Statement, a więc i te
omawiane. Otóż nie. Obiekty Statement nie zawierają wyrażenia SQL, które musi być
podane jako argument do ich metod. W przypadku obiektu PreparedStatement
wyrażenie SQL musi być przygotowane – obiekt zawiera prekompilowane wyrażenie
SQL. Dlatego wykonanie odpowiedniego polecenia polega na wywołaniu metody dla
obiektu PreparedStatement bez podawania żadnego argumentu.
Poniżej przedstawiono porównanie wykonania polecenia SQL dla obiektu Statement
oraz obiektu PreparedStatement:
Statement:
stat i ic Str i ing SQL = "INSERT INTO kurs VALUES ( ' 'Mar i iusz ' ', ' 'MK ' ', 28)";
Statement s=...
s.executeUpdate(SQL);
PreparedStatement:
Connect i ion c=...
PreparedStatement ps = c.prepareStatement("INSERT INTO kurs VALUES (?, ?,
?)");
ps.setStr i ing( 1 1,"Mar i iusz");
ps.setStr i ing(2,"MK");
ps.setInt( 1 1, 28);
ps.executeUpdate();
W pracy z zewnętrznymi procedurami przechowywanymi poza kodem programu
istotą wykorzystania Javy jest stworzenie wyrażenia typu CallableStatement poprzez
podanie jako parametru metody Connection.prepareCall() sekwencji ucieczki typu
{call procedure_name[(?, ?)]} lub {? = call procedure_name[(?, ?)]} w przypadku gdy
procedura zwraca wartość. Jak widać istota polega na znajomości nazwy i
parametrów obsługiwanej procedury. Parametry ustawia się tak jak dla wyrażeń
PreparedStatement natomiast pobiera się metodami getXXX(). Wykonanie polecenia
(poleceń) procedury odbywa się poprzez wykorzystanie metody execute().
Posiadając wiedzę na temat stworzenia połączenia oraz przygotowywania i
wykonywania wyrażeń można wykonać dwa przykładowe programy. Programy te
wymagają ustawienia w ODBC systemu Win95/NT (Panel sterowania): dodanie
ODBC typu plik tekstowy, nazwa udziału: kurs, katalog: c:\kurs\java. Ustawienia te są
konieczne ponieważ wykorzystany zostanie pomost JDBC-ODBC jako sterownik do
bazy danych. Obydwa programy generują to samo: bazę danych (pliki) o nazwie kurs
9-7
Jacek Rumi ń ski - J ę zyk JAVA –
Zgłoś jeśli naruszono regulamin