Relacyjne Bazy Danych
wykład XIII
JDBC - programistyczny interfejs do bazy danych
Na tym wykładzie, dla porównania, przedstawimy tak samo popularny jak ADO interfejs
programistyczny do bazy danych – mianowicie JDBC. Należy on do środowiska języka
programowania Java i będzie używany na
zajęciach dotyczących Javy. Nas interesuje tutaj przede wszystkim porównanie ADO z JDBC - jak bardzo są do siebie podobne, co nie powinno
stanowić niespodzianki bo oba są oparte na tym
samym standardzie interfejsu poziomu wywołań
(CLI) języka SQL.
JDBC
W związku z popularnością języka Java w dziedzinie aplikacji bazodanowych zostały opracowane dwie wersje:
•języka SQL osadzonego w Javie o nazwie SQLJ;
•interfejsu programistycznego SQL z języka Java o nazwie JDBC.
Interfejs JDBC stał się popularny i jest używany między innymi w:
•programach aplikacyjnych napisanych w Javie - po stronie klienta;
•apletach czyli małych programach Javy realizowanych na przeglądarce użytkownika;
•serwletach czyli programach Javy spełniających rolę małych serwerów aplikacyjnych to jest programów realizujących przez sieć zlecenia użytkowników;
•procedurach i funkcjach zakodowanych w Javie składowanych w bazie danych.
JDBC jest zbiorem klas i interfejsów w Javie, które umożliwiają dostęp do bazy danych z programów napisanych w Javie. Klasy te i interfejsy tworzą pakiet java.sql.
Na początku programu zamieszcza się zwykle dyrektywę importu:
import java.sql.*;
Do określenia sposobu łączenia się z bazą danych służy napis połączenia URL (jdbc oznacza nazwę głównego protokołu połączenia):
jdbc:<podprotokół>:<podnazwa>
np.
jdbc:odbc:moja_baza
jdbc:oracle:thin:@xeon.pjwstk.waw.pl:1521:ORCL
Sterownik JDBC - zestaw klas, które implementują
interfejsy pakietu java.sql dla konkretnego systemu baz danych.
Aby połączyć się z bazą danych należy wykonać dwie instrukcje:
Krok 1: załadowanie odpowiedniego sterownika JDBC do pamięci:
- albo za pomocą mechanizmu Javy dynamicznego ładowania klas:
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
- albo używając statycznej metody registerDriver klasy DriverManager:
DriverManager.registerDriver(new sun.jdbc.odbc.JdbcOdbcDriver());
Krok 2: użycie metody getConnection klasy DriverManager do otwarcia połączenia z bazą danych, która zwraca referencję do obiektu klasy Connection.
String URL = "jdbc:odbc:moja_baza"
Connection con =
DriverManager.getConnection(URL, "użytkownik",
"hasło");
Obiekty JDBC
Zasady korzystania z podstawowych obiektów klas interfejsu JDBC są następujące:
• Sesja z bazą danych rozpoczyna się od utworzenia obiektu klasy Connection (odpowiednik klasy Connection w ADO).
• Obiekt klasy Statement reprezentuje wykonywaną instrukcję SQL (odpowiednik klasy Command w ADO). Podstawowe dwie metody to:
•executeQuery - jako parametr bierze tekst zapytania SQL a zwraca obiekt typu ResultSet – z danymi.
•executeUpdate – jako parametr bierze instrukcję SQL i zwraca liczbę przetworzonych przez nią w bazie danych rekordów.
•Obiekt klasy ResultSet reprezentuje zbiór rekordów zwracanych przez zapytanie - przy czym dokładnie jeden rekord jest dostępny w danej chwili (odpowiednik klasy RecordSet w ADO).
•Kolejne rekordy uzyskuje się stosując metodę next, która zwraca wartość logiczną, przy czym:
•false oznacza, że doszliśmy do końca zbioru wynikowego rekordów.
•Poszczególne wartości pól uzyskuje się stosując metody takie jak getString i getFloat, które mając daną nazwę pola
(odpowiedniego typu) zwracają wartość tego pola w bieżącym rekordzie.
•Obiekt klasy SQLException reprezentuje błąd (wyjątek) związany z wykonywaniem instrukcji SQL na bazie danych.
Przykład zastosowania interfejsu JDBC do bazy danych określonej przez połączenie ODBC o nazwie oras z logowaniem na konto
"scott" z hasłem "tiger". Zakładamy, że w bazie danych znajduje się tabela Emp mająca kolumny: Ename typu napisowego oraz Sal typu numerycznego.
//połącz się z bazą danych
try{Class.forName("sun.jdbc.odbc.JdbcOdbcDriver
");}
catch(ClassNotFoundException ex) {
System.out.println(ex.getMessage ());
} try {
Connection con =
DriverManager.getConnection("jdbc:odbc:oras",
"scott", "tiger");
//zbuduj obiekt reprezentujący instrukcję SQL i wykonaj ją Statement stmt = con.createStatement();
String query = "SELECT Ename, Sal FROM Emp";
ResultSet rs = stmt.executeQuery(query);
//przejdź w pętli po wszystkich wierszach wynikowych while (rs.next()) {
String s = rs.getString("Ename");
float z = rs.getFloat("Sal");
System.out.println(s + ": " + z);
}
} catch(SQLException ex) {// obsłuż wyjątki System.out.println(ex.getMessage ()
+ ex.getSQLState () + ex.getErrorCode ());
} }
W przykładzie został użyty sterownik typu most między JDBC a ODBC.
Można byłoby użyć innego sterownika, na przykład sterownika firmy Oracle.
Wtedy przykładowo URL =
"jdbc:oracle:thin:@elektron.pjwstk.edu.pl:1521:ORC L".
Jako ćwiczenie, można sprawdzić działanie załączonego pełnego programu w Javie - obejmującego powyższy przykład dla bazy danych MS Access.
Modyfikowanie danych w bazie danych
Statement stm = con.createStatement();
int liczba = stm.executeUpdate(
"UPDATE Emp SET Sal = Sal*1.1");
System.out.println(
"Podniesiono zarobki o 10%: "+ liczba+" osobom.");
stm.close();
Wywołanie stm.executeUpdate zwraca pojedynczą liczbę, określającą liczbę wierszy tabeli, których dotyczyło zapytanie (tzn. które zostały zaktualizowane). Metoda
stm.executeUpdate używana jest do wykonywania operacji: INSERT, UPDATE, DELETE, a także operacji definiowania danych takich jak: CREATE TABLE, ALTER TABLE, DROP TABLE.
Modyfikowanie danych w bazie danych przy użyciu obiektu ResultSet Statement stm =
con.createStatement(ResultSet.TYPE_SCROLL_SENSI TIVE, ResultSet.CONCUR_UPDATABLE)
String sql = "SELECT * FROM Emp";
ResultSet rs = stm.executeQuery(sql);
rs.first();
rs.updateString("Ename","Kowalski");
rs.updateFloat("Sal",10000);
rs.updateRow();
Należy zdawać sobie sprawę, że nie każdy system obsługuje modyfikowalne obiekty ResultSet (podobnie jest dla obiektów RecordSet w ADO).
Usunięcie bieżącego rekordu rs.deleteRow();
Dodanie nowego rekordu
rs.moveToInsertRow();
rs.updateString("Ename","Kowalski");
rs.updateFloat("Sal", 10000);
rs.insertRow();
Obsługa transakcji
Domyślnie w JDBC każda instrukcja SQL kończy się automatycznym zatwierdzeniem (auto-commit). Poniżej zmieniamy to domyślne ustawienie. Gdy wykonywanie wszystkich instrukcji SQL kończy się pomyślnie, explicite wykonujemy zatwierdzanie przy pomocy metody commit
obiektu Connection. Gdy w trakcie wykonywania instrukcji SQL powstanie błąd, wykonujemy wycofanie transakcji przy pomocy metody rollback obiektu Connection.
try {
con.setAutoCommit(false);
Statement stm=con.createStatement();
stm.executeUpdate(" ...");
stm.executeUpdate(" ...");
...
con.commit();
}
catch(Exception e){
con.rollback();
}
Obsługa NULL - funkcja wasNull()
float Sal = rs.getFloat("Sal");
if (rs.wasNull(){
Sal = 0;
}
Przygotowanie instrukcji - PreparedStatement
Gdy wielokrotnie wykonuje się tę samą instrukcję, warto ją wcześniej raz przygotować dokonując analizy składniowej, a potem wykonywać wielokrotnie. Co więcej, taka instrukcja może mieć parametry zmieniane przy każdym wywołaniu. W miejsce klasy Statement korzystamy w tym przypadku z klasy PreparedStatement. Parametry formalne są w treści
instrukcji oznaczone przez znaki zapytania:
PreparedStatement stmt =
con.prepareStatement("UPDATE Emp SET Deptno
= ? WHERE Deptno = ?");
Następujące metody służą do nadania wartości parametrom:
setInt(), setString(), setDate() etc. Każda z nich ma dwa argumenty: numer parametru i jego wartość. Po przygotowaniu można wielokrotnie nadawać różne wartości temu samemu
parametrowi. Oto przykładowy fragment kodu, który przenosi wszystkich pracowników z działu numer 10 do działu nr 50.
PreparedStatement stmt = con.prepareStatement(
"UPDATE Emp SET Deptno = ? WHERE Deptno = ?");
stmt.setInt(1, 50);
stmt.setInt(2, 10);
System.out.println(stmt.executeUpdate()+" przeniesionych");
stmt.close();
Podsumowanie
Na dwóch ostatnich wykładach czytelnik zaznajomił się z
programistycznym interfejsem poziomu wywołań czyli ze sposobem wykonywania w programie konwencjonalnego języka
programowania instrukcji SQL na bazie danych. Sposób ten polega na zainicjowaniu połączenia z bazą danych przy pomocy obiektu klasy Connection. Następnie korzystając z odpowiednich metod albo samego obiektu klasy Connection albo obiektu
reprezentującego instrukcję SQL czyli obiektu klasy Command w VBA i Statement w Javie następuje wykonanie instrukcji
SQL. W przypadku wykonywania instrukcji SELECT otrzymywane z bazy danych wiersze są zapisywane i przetwarzane przy pomocy metod obiektu RecordSet w VBA i ResultSet w Javie.
JDBC - zbiór klas i interfejsów w Javie, które umożliwiają dostęp do bazy danych z programów napisanych w Javie. Klasy te i
interfejsy tworzą pakiet java.sql.*
sterownik JDBC - zestaw klas, które implementują interfejsy pakietu java.sql dla konkretnej bazy danych.
Connection - klasa, której obiekty reprezentują połączenie z bazą danych w celu wykonania ciągu instrukcji SQL.
Statement - klasa, której obiekty reprezentują instukcję SQL.
ResultSet - klasa, której obiekty reprezentują zbiór rekordów zwracanych przez zapytanie – przy czym jeden rekord jest dostępny w danej chwili.
przygotowanie instrukcji - gdy wielokrotnie wykonuje się tę samą instrukcję, warto ją wcześniej raz przygotować (zanalizować
składniowo), a potem wykonywać wielokrotnie. Co więcej, taka instrukcja może mieć parametry zmieniane przy każdym
wywołaniu.