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:ORCL". 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_SENSITIVE, 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 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.
Koniec Wykładu XIII