1
Obsługa baz danych przy
użyciu JDBC
Beata Pańczyk - Java (Wykład 11)
2
ODBC
• ODBC (Open DataBase Connectivity - otwarte
łącze baz danych) - interfejs programowania baz
danych opracowany w firmie Microsoft, który
pozwala wszystkim aplikacjom Windows
korzystającym z baz danych za pośrednictwem sieci
posługiwać się tym samym zbiorem wywołań
• W skład ODBC wchodzą wywołania wbudowane
w aplikacje oraz sterowniki ODBC
3
JDBC
• JDBC (Java DataBase Connectivity) - łącze do baz
danych w języku Java
• interfejs programowania opracowany w 1996 r. przez
Sun Microsystems, umożliwiający niezależnym od
platformy aplikacjom napisanym w języku Java
porozumiewać się z bazami danych za pomocą
języka SQL
• interfejs ten jest odpowiednikiem zaprojektowanego
przez Microsoft łącza ODBC
4
Programowanie bazodanowe
w Javie
• aplikacje bazodanowe programowane w tradycyjnych
językach - zależne od architektury konkretnej bazy danych
• w Javie - niezależność dzięki wprowadzeniu interfejsu
JDBC, który
– operuje na poziomie języka SQL
– ukrywa przed programistą specyficzne własności i
ustawienia bazy danych
• program napisany w Javie – działa z dowolną bazą danych
– obsługującą ten sam standard SQL-a
– wspierającą technologię JDBC
• klasy i interfejsy JDBC – dostępne w pakiecie java.sql
5
Praca z bazą danych poprzez
JDBC
•
załadowanie sterownika JDBC
•
zdefiniowanie adresu URL połączenia
•
nawiązanie połączenia
•
utworzenie obiektu Statement
•
wykonanie zapytania lub aktualizacja danych
•
przetworzenie wyników
•
zamknięcie połączenia
6
Sterowniki
• sterownik JDBC - zestaw klas implementujących
interfejsy JDBC dla określonej bazy danych
• zazwyczaj pisane przez producentów baz danych
• z jednej strony przyjmują połączenia JDBC
i instrukcje, a z drugiej wysyłają wywołania do
bazy danych
2
7
Kategorie sterowników
1. JDBC-ODBC bridge driver
(technologia pomostowa między JDBC a ODBC
Microsoftu)
2. Native API partly–Java driver
(biblioteki napisane w innych językach)
3. JDBC-Net pure Java driver
(standardowe interfejsy sieciowe)
4. Native–protocol pure Java driver
(protokoły sieciowe wbudowane w maszyny
bazodanowe)
8
Kategorie sterowników
• Sterowniki typu 1 i 2
– często rozpowszechniane za darmo (np. w SDK)
– wymagają instalacji dodatkowego oprogramowania po
stronie klienta
• Sterowniki typu 3 i 4
– zwykle odpłatne
– nie wymagają żadnych dodatkowych instalacji
• Aktualna lista dostępnych na rynku sterowników - na
stronie java.sun.com
9
Klasa DriverManager
• w celu nawiązania połączenia z bazą danych środowisko
wykonawcze Javy musi załadować odpowiedni sterownik
dla danej bazy
• za ładowanie i usuwanie z pamięci sterowników
odpowiedzialna jest klasa DriverManager (zarządca
sterowników), która:
– dynamicznie zarządza obiektami sterowników
zachowując kontekst zabezpieczeń każdego sterownika
– kontekst zabezpieczeń definiuje środowisko, w jakim
aplikacja jest uruchamiana
– porównuje kontekst zabezpieczeń sterownika
z kontekstem programu (sprawdza czy są takie same)
10
Droga od kodu Javy do bazy danych
Program Java
Menedżer sterowników
Sterownik
Wewnętrzny sterownik
Baza danych
JDBC
Baza
danych
DriverManager
utrzymuje
strukturę danych
zawierającą
obiekty Driver
oraz informacje
o nich
11
Ładowanie sterownika
Przy pomocy wiersza poleceń:
• żeby wykorzystać sterownik JDBC trzeba go załadować
• należy określić sterownik do załadowania przy użyciu
zmiennej systemowej jdbc.drivers
• pomost JDBC-ODBC załaduje polecenie:
java –Djdbc.drivers=sun.jdbc.JdbcOdbcDriver nazw_apl
W programach (mniej elastyczne):
• użytkownik końcowy nie może w prosty sposób zmienić
wersji bazy danych
• łatwiejsze w codziennym użytkowaniu
12
Rejestracja sterownika
• wywołanie metody Class.forName()
• argument metody (typu String) określa sterownik, np. dla
technologii pomostowej JDBC-ODBC jest to:
"sun.jdbc.odbc.JdbcOdbcDriver"
• załadowanie sterownika – aby zapewnić elastyczność kodu
należy unikać podawania na stałe nazwy używanej klasy
sterownika, np.
try {
Class,forName("connect.microsoft.MicrosoftDriver");
Class.forName("oracle.jdbc.driver.OracleDriver");
Class.forName("com.sybase.jdbc.SybDriver");
}
catch (ClassNotFoundException exp)
{ System.out.println("Błąd ładowania sterownika: "+exp);}
3
13
Określenie adresu URL połączenia
• adresy URL odwołujące się do baz danych wykorzystują protokół
jdbc: i zawierają informacje o nazwie komputera na którym działa
serwer bazy danych, numer używanego portu oraz nazwę bazy
danych
• format zapisu adresu URL – podany w dokumentacji dostarczonej
z konkretnym sterownikiem JDBC
• np.:
String host="dbhost.firma.com.pl";
String db="nazwaBazy";
int port=1234;
String oracleURL = "jdbc:oracle:thin:@" + host + ":" + port + ":" + db;
String sybaseURL = "jdbc:sybase:Tds:"+ host + ":" + port + ":" +
"?SERVICENAME" +db;
String msaccessURL = "jdbc:odbc" +db ;
14
Nawiązanie połączenia - klasa
Connection
• po zarejestrowaniu sterownika program łączy się za jego pomocą
z bazą danych
• nawiązanie połączenia realizuje metoda
getConnection
klasy
DriverManager:
DriverManager.getConnection("url","user","pass");
• wywołanie metody może zgłosić wyjątek SQLException
• metoda zwraca obiekt klasy
Connection
• np.:
String user="beatap";
String haslo="tajne";
Connection polaczenie = DriverManager.getConnection(
oracleURL, user, haslo);
15
Interfejs Connection
• prepareStatement – tworzy prekompilowane zapytania do
przesłania do bazy danych
• prepareCall – metoda odwołuje się do procedur
zachowanych, przechowywanych na serwerze BD
• rollback, commit – metody do obsługi transakcji; commit -
zatwierdza zmiany, rollback - odrzuca wszystkie zmiany
dokonane od ostatniego wywołania commit
• setAutoSubmit() - wyłącza opcję automatycznego
dokonywania zmian
• close – zamyka otwarte połączenie z bazą danych
• isClosed – sprawdza czy nie skończył się okres ważności
połączenia lub czy nie zostało ono jawnie zamknięte
• getMetaData – zwraca obiekt DataBaseMetaData
16
Informacje o bazie danych
• Metody obiektu DatabaseMetaData:
– getDatabaseProductName – nazwa BD
– getDatabaseProductversion – numer wersji BD
– getDriverName – nazwa sterownika JDBC
– getDriverVersion – numer versji sterownika
• Np.:
DatabaseMetaData dbmeta = polaczenie.getMetaData();
String nazwaBazy = dbmeta. getDatabaseProductName();
System.out.println("Baza danych: " + nazwaBazy );
String numerwersji = dbmeta. getDatabaseProductversion();
System.out.println("Numer wersji bazy: " + numerwersji);
17
Utworzenie polecenia - obiekt
Statement
• do przesyłania zapytań i poleceń do BD są
wykorzystywane obiekty Statement
• metoda createStatement() utworzonego obiektu
klasy Connection zwraca obiekt Statement
• np.
Statement polecenie=polaczenie.createStatement();
• większość sterowników JDBC pozwala na
jednoczesne tworzenie i używanie większej liczby
obiektów Statement korzystających z tego samego
połączenia z BD
18
Wykonanie zapytania
• dysponując obiektem Statement można już
przesłać zapytanie SQL
• executeQuery – przesyła zapytanie i w wyniku
zwraca obiekt ResultSet przechowujący wiersze
tabeli wyników
• np.
String zapytanie = "SELECT * FROM books";
ResultSet wynik = polecenie.executeQuery(zapytanie);
4
19
Interfejs Statement – przesyłanie i
wykonywanie dowolnych poleceń SQL
• executeQuery – wykonuje polecenie SQL i zwraca dane w postaci
obiektu ResultSet (obiekt może być pusty ale metoda nie zwraca null)
• executeUpdate – realizuje polecenia SQL UPDATE, INSERT,
DELETE i zwraca liczbę rekordów objętych działaniem
poszczególnych poleceń (również 0); obsługuje także polecenia
CREATE TABLE, DROP TABLE, ALTER TABLE
• executeBatch – wykonuje grupę poleceń SQL jako jedną całość i
zwraca tablicę wierszy objętych działaniem poszczególnych poleceń;
dodawanie poleceń do grupy – metoda addBatch
• setQueryTimeout – określa czas przez jaki sterownik będzie czekał na
odebranie wyników zanim zgłosi wyjątek SQLException
• getMaxRows, setMaxRows – max liczba wierszy jaką może zawierać
obiekt ResultSet (domyślnie 0 – nie ograniczona)
20
Obiekty Statement i ResultSet
program Java
JDBC & Driver
baza danych
czas
Statement(SQL)
ResultSet
Statement(SQL)
ResultSet
Baza
danych
21
Interfejs ResultSet -
przetworzenie wyników
• metoda next() zwraca kolejny wiersz lub
false
jeśli
osiągnięto koniec zbioru wynikowego
• getXxx – metody zwracające wartości niemal wszystkich
podstawowych typów danych (np. getString(), getInt() )
• UWAGA! Kolumny zbioru wynikowego są indeksowane
(zgodnie z konwencją przyjętą
w SQL) od 1 a nie od 0.
• odczytując dane przechowywane w obiekcie ResultSet,
lepiej jest używać nazw kolumn (nie ich indeksów) – w
przypadku zmiany struktury tabeli niebezpieczeństwo
awarii kodu obsługującego wyniki jest mniejsze
22
Przykład – wyświetlenie
wyników
String host="dbhost.firma.com.pl"; String db="nazwaBazy"; int port=1234;
String URL = "jdbc:odbc" +db ;
String user="beatap"; String haslo="tajne";
Connection polaczenie = DriverManager.getConnection(URL, user, haslo);
Statement polecenie=polaczenie.createStatement();
String zapytanie = "SELECT * FROM znajomi";
ResultSet wynik = polecenie.executeQuery(zapytanie);
while (wynik.next())
{
int id = wynik.getInt("id");
String n = wynik.getString("nazwisko");
String i = wynik.getString("imie");
String e = wynik.getString("email");
System.out.println(id+" "+n+" "+i+" "+e); }
polaczenie.close();
23
Interfejs ResultSet
• next(), previous()
• relative(int)
– przesuwa kursor o podaną liczbę wierszy do
przodu lub do tyłu (wartość ujemna)
• absolute(int)
– przesuwa kursor do wiersza o wskazanym
numerze
• getXxx
– zwraca wartość odczytaną z wiersza o podanej
nazwie lub indeksie
• wasNull
– sprawdza czy wartość odczytana przez ostatnie
wywołanie metody getXxx jest Null
• findColumn
– zwraca indeks kolumny o podanej nazwie
• getRow
– zwraca numer bieżącego wiersza (numerowane
od 1)
• getMetaData
– zwraca obiekt typu ResultSetMetaData
opisujący zawartość ResultSet
24
Interfejs ResultSetMetaData
• getColumnCount
• getColumnName(int)
• getColumnType
– zwraca wartość int do
porównania ze stałymi klasy java.sql.Types
• isReadOnly
– czy wskazana kolumna tylko do
odczytu
• isSearchable
– czy wskazana kolumna może być
zastosowana w klauzuli WHERE
• isNullable
- czy wskazana kolumna może
zawierać NULL
5
25
Zamknięcie połączenia
• polaczenie.close();
• Zamknięcie połączenia powoduje również zamknięcie
używających go obiektów
Statement
i
ResultSet
• Jeżeli planowane jest przeprowadzenie innych operacji na
BD – nie należy zamykać połączenia przed ich
wykonaniem (koszt otwarcia nowego połączenia jest dość
wysoki)
• W praktyce stosowanie już otwartych połączeń jest bardzo
ważnym aspektem optymalizacji korzystania z baz danych
• API JDBC – definiuje specjalny interfejs
ConnectionPoolDataSource
do korzystania z pul
połączeń
26
Instalacja i konfiguracja
serwera MySQL
• pobranie MySQL ze strony
http://dev.mysql.com/downloads/ i zainstalowanie
jako usługi systemowej (w Windows) –
sczególowe informacje na stronie
http://dev.mysql.com/doc/
• utworzenie bazy danych
• utworzenie użytkownika
• instalacja sterownika JDBC
27
Instalacja sterownika JDBC
• najczęściej stosowane sterowniki do połączenia
z MySQL (dostępne w plikach JAR):
– MySQL Connector/J (zalecany przez twórców MySQL)
– Caucho Resin
• żaden z tych sterowników nie jest w pełni zgodny ze
specyfikacją JDBC 2.0 ani ze standardem ANSI SQL-92
• podczas tworzenia aplikacji w zmiennej środowiskowej
CLASSPATH należy podać ścieżkę dostępu do pliku JAR
sterownika
• podczas wdrażania aplikacji – plik sterownika należy
umieścić (dla serwera Tomcat) w folderze WEB-INF/lib lub
we wspólnym folderze kat_instalacyjny/common/lib (jeśli na
serwerze działa wiele aplikacji WWW korzystających z bd)
28
Sterownik MySQL Connector/J
• do pobrania ze strony:
http://www.mysql.com/products/connector-j/
• umieszczony w pliku:
mysql-connector-java-3.1.14\mysql-connector-java-
3.1.14-bin.jar
• klasa sterownika:
com.mysql.jdbc.Driver
• URL używany do połączenia z bazą danych:
jdbc:mysql://komputer:3306//NazwaBazy
29
Sterownik Caucho Resin
• do pobrania ze strony:
http://www.caucho.com/projects/jdbc-mysql/index.xtp
• umieszczony w pliku:
caucho-jdbc-2.1.0.jar
• klasa sterownika:
com.caucho.jdbc.mysql.Driver
• URL używany do połączenia z bazą danych:
jdbc:mysql-caucho://komputer:3306//NazwaBazy
• wg. danych firmy Caucho sterownik jest 50%
szybszy od sterownika MySQL Connector/J
30
Przykład 1 – wyświetlanie
danych z bazy MYSQL
import java.sql.*;
public class testBD {
public static void main(String[] args)
throws SQLException, ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver");
Connection polacz =
DriverManager.getConnection("jdbc:mysql://localhost:3306/
dane", "root", "");
Statement zapytanie = polacz.createStatement();
ResultSet w = zapytanie.executeQuery
("SELECT * FROM news");
6
31
Przykład 1 – c.d.
while (w.next())
{
int id = w.getInt("Lp");
String n = w.getString("Naglowek");
String i = w.getString("Tresc");
String e = w.getString("Autor");
System.out.println(id+" "+n+" "+i+" \n"+e);
}
polacz.close();
}
}
32
33
Przykład 1a
• Przykład zmodyfikowanego zapytania SQL
ResultSet w = zapytanie.executeQuery(
"SELECT Autor FROM news");
while (w.next())
{
String n = w.getString("Autor");
System.out.println(n);
}
34
Przykład 1b – dodawanie
rekordów do bazy
Statement zapytanie = polacz.createStatement();
int x = zapytanie.executeUpdate( "INSERT INTO news
(Autor, Naglowek, Tresc) VALUES ('Wilk', 'Tytul', 'Tresc')");
System.out.println("Dodano rekordow: " + x);
35
Netbeans 6.5 i serwer JavaDB
36
Połączenie z Network Java DB
projektu w NetBeans
• w strukturze projektu wskazać
Libraries
oraz
wybrać
Add JAR/Folder...
(pod prawym przyciskiem)
• wskazać ścieżkę do
\db\lib\derbyclient.jar
(np. ...sun\JavaDB\lib\derbyclient.jar )
• W aplikacji przetestować przykładowy kod:
Class.forName("org.apache.derby.jdbc.ClientDriver");
Connection conn=
DriverManager.getConnection("jdbc:derby://localhost:1527/db", "app",
"app");
ResultSet rs =
conn.createStatement().executeQuery("SELECT * FROM db_table");
while(rs.next()){ System.out.println(rs.getString(2)); }
7
37
Połączenie z Embedded Java DB
projektu w NetBeans
• w strukturze projektu wskazać
Libraries
oraz
wybrać
Add JAR/Folder...
(pod prawym przyciskiem)
• wskazać ścieżkę do
\db\lib\derby.jar
(np. ...sun\JavaDB\lib\derby.jar )
• W aplikacji przetestować przykładowy kod:
Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
Connection conn=
DriverManager.getConnection("jdbc:derby:db", "app", "app");
ResultSet rs =
conn.createStatement().executeQuery("SELECT * FROM db_table");
while(rs.next()){ System.out.println(rs.getString(2)); }
38
Baza testbp z tabelą studenci
39
Rekordy tabeli studenci
40
Przykład 2 – połączenie z JavaDB
import java.sql.*;
public class Main {
public static void main(String[] args) throws SQLException,
ClassNotFoundException {
Class.forName("org.apache.derby.jdbc.ClientDriver");
Connection conn=
DriverManager.getConnection("jdbc:derby://localhost:1527/testbp",
"beatap", "beatap");
ResultSet rs =
conn.createStatement().executeQuery("SELECT * FROM studenci");
while(rs.next()){ System.out.println(rs.getString(2)); }
}
}
41
Przykład 2 - wynik
42
Zalety JDBC
• łatwość użycia (dzięki temu, że jest już
zdefiniowany interfejs i wszystkie mechanizmy do
obsługi baz danych, pozostaje jedynie z niego
skorzystać)
• uniwersalność (jak z każdego produktu SUN
z JDBC można korzystać na każdej platformie;
obsługa różnych rodzajów baz danych (Oracle,
Access, MySQL itd.) jest bardzo podobna
8
43
Wady JDBC
• niska wydajność (ponieważ jest to interfejs - zanim
zapytanie powędruje do bazy danych, jest ono
przetwarzane do postaci uniwersalnej, rozumianej
przez wszystkie systemy oraz bazy danych; nawet
jeśli użytkownik pracuje na dwóch identycznych
bazach danych, to i tak komunikacja między nimi
sprowadza się do tłumaczenia na "język uniwersalny"
a dopiero potem dostarczania docelowej bazie
danych)
• niski poziom bezpieczeństwa (aby komunikacja
z bazą danych mogła przebiegać w miarę szybko
i być przy tym uniwersalna poziom bezpieczeństwa
jest tutaj na niezbyt wysokim poziomie)