Relacyjne Bazy Danych wykład XIII 1 opr. Lech Banachowski, Jan Wierzbicki 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. 2 opr. Lech Banachowski, Jan Wierzbicki 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. 3 opr. Lech Banachowski, Jan Wierzbicki 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. 4 opr. Lech Banachowski, Jan Wierzbicki 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.*; 5 opr. Lech Banachowski, Jan Wierzbicki 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 6 opr. Lech Banachowski, Jan Wierzbicki 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()); 7 opr. Lech Banachowski, Jan Wierzbicki 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"); 8 opr. Lech Banachowski, Jan Wierzbicki 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. 9 opr. Lech Banachowski, Jan Wierzbicki •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. 10 opr. Lech Banachowski, Jan Wierzbicki 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"); 11 opr. Lech Banachowski, Jan Wierzbicki //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 ()); } } 12 opr. Lech Banachowski, Jan Wierzbicki 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. 13 opr. Lech Banachowski, Jan Wierzbicki 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. 14 opr. Lech Banachowski, Jan Wierzbicki Modyfikowanie danych w bazie danych przy użyciu obiektu ResultSet Statement stm = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIV E, 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). 15 opr. Lech Banachowski, Jan Wierzbicki Usunięcie bieżącego rekordu rs.deleteRow(); Dodanie nowego rekordu rs.moveToInsertRow(); rs.updateString("Ename","Kowalski"); rs.updateFloat("Sal", 10000); rs.insertRow(); 16 opr. Lech Banachowski, Jan Wierzbicki 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. 17 opr. Lech Banachowski, Jan Wierzbicki try { con.setAutoCommit(false); Statement stm=con.createStatement(); stm.executeUpdate(" ....."); stm.executeUpdate(" ....."); ..... con.commit(); } catch(Exception e){ con.rollback(); } 18 opr. Lech Banachowski, Jan Wierzbicki Obsługa NULL - funkcja wasNull() float Sal = rs.getFloat("Sal"); if (rs.wasNull(){ Sal = 0; } 19 opr. Lech Banachowski, Jan Wierzbicki 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 = ?"); 20 opr. Lech Banachowski, Jan Wierzbicki 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(); 21 opr. Lech Banachowski, Jan Wierzbicki 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. 22 opr. Lech Banachowski, Jan Wierzbicki 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. 23 opr. Lech Banachowski, Jan Wierzbicki 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. 24 opr. Lech Banachowski, Jan Wierzbicki Koniec Wykładu XIII 25 opr. Lech Banachowski, Jan Wierzbicki