InMoST Wielkopolska sieć współpracy w zakresie innowacyjnych metod wytwarzania oprogramowania Termin realizacji: 01.08.2005 – 31.07.2007 Dostęp do baz danych przez interfejs JDBC Bartosz Walter Szkolenie finansowane ze środków Europejskiego Funduszu Społecznego (75%) i budżetu państwa (25%) w ramach Zintegrowanego Programu Operacyjnego Rozwoju Regionalnego Wprowadzenie JDBC (Java DataBase Connectivity) jest biblioteką Javy (zbiorem interfejsów i klas) służącą do wykonywania operacji na bazach danych JDBC z punktu widzenia aplikacji nie zależy od wykorzystywanego systemu bazy danych, dzięki czemu stosunkowo łatwo zmienić go na inny Biblioteka znajduje się w Java SDK w pakietach java.sql.* i javax.sql.* Odczyt informacji z bazy danych 1. Załadowanie sterownika JDBC specyficznego dla konkretnej bazy danych (MySQL, PostgreSQL, Oracle etc.) i zarejestrowanie go w JVM 2. Utworzenie obiektu Connection, reprezentującego połączenie z bazą danych 3. Utworzenie obiektu Statement, reprezentującego instrukcję do wykonania w bazie danych 4. Wykonanie instrukcji; w przypadku zapytań – pobranie obiektu ResultSet udostępniającego wyniki 5. Przetworzenie obiektu ResultSet 6. Zamknięcie obiektów ResultSet, Statement i Connection Sterownik JDBC baza danych komunikacja z serwerem bazy danych sterownik Sterownik JDBC jest niewielką biblioteką umożliwiającą operacje na bazie danych specyficznej dla sterownika Każdy system zarządzania bazą danych wymaga własnego sterownika JDBC. Są one dostarczane przez producentów systemów zarządzania bazami danych protokół JDBC Aplikacja użytkownik Ładowanie sterownika JDBC Sterownik JDBC musi być widoczny dla aplikacji, tzn. musi znajdować się na jej ścieżce klas (CLASSPATH) W Eclipse wystarczy dołączyć bibliotekę do projektu Załadowanie klasy sterownika Class.forName("org.hsqldb.jdbcDriver"); // w przypadku braku klasy – wyjątek SQLException DriverManager.registerDriver( new org.hsqldb.jdbcDriver()); // w przypadku braku klasy – wyjątek ClassNotFoundEx. Utworzenie obiektu Connection Obiekt Connection reprezentuje fizyczne połączenie do bazy danych Connection conn = DriverManager.getConnection( "jdbc:hsqldb:hsql:@localhost", "student", "wsb"); URL bazy danych nazwa użytkownika i hasło jdbc:hsqldb:hsql:@komputer.domena.pl:9001/bazadanych protokół adres serwera port nazwa bazy danych Utworzenie obiektu Statement Obiekt Statement reprezentuje instrukcję języka SQL, którą możemy wykonać w danym połączeniu Tworzeniem obiektu Statement zajmuje się obiekt Connection Obiekt Statement zajmuje się m.in.. weryfikacją poprawności polecenia Statement stm = conn.createStatement(); Utworzenie obiektu Statement – cd. W przypadku wielokrotnego wykonywania tej samej operacji SQL z różnymi danymi można skorzystać z obiektu PreparedStatement PreparedStatement w odróżnieniu od obiektu Statement nie wykonuje za każdym razem weryfikacji poprawności polecenia SQL, co poprawia wydajność PreparedStatement pstm = conn.prepareStatement("SELECT * FROM STUDENCI"); Utworzenie obiektu Statement – cd. Obiekt PreparedStatement może uwzględniać niekonkretne wartości atrybutów polecenia SQL, które będą ukonkretniane w momencie wykonywania polecenia Pozwala to na efektywniejsze wykonywanie poleceń PreparedStatement pstm = conn.prepareStatement( "select * from STUDENCI where ID=? and IMIE=?"); pstm.setInt(1, 100); pstm.setString(2, 'Jan'); ResultSet rs = pstm.executeQuery(); Wykonanie polecenia SQL Obiekt Statement wykonuje przekazane mu polecenie W przypadku zapytań wynikiem wykonania polecenia jest obiekt ResultSet, który zawiera odczytane informacje z bazy danych W przypadku poleceń INSERT lub UPDATE wynikiem jest wartość int oznaczająca liczbę zmodyfikowanych rekordów ResultSet rs = stm.executeQuery( "SELECT * FROM STUDENCI"); int liczbaRekordów = stm.executeUpdate( "INSERT INTO STUDENCI values (1, "Nowak", "Jan"); Przetwarzanie obiektu ResultSet Obiekt ResultSet jest obiektem, który zawiera pierwszy rekord danych Odczyt kolejnych rekordów odbywa się przez wywołanie metody next(), która określa też, czy kolejny rekord istnieje ResultSet rs = stm.executeQuery( "SELECT * FROM STUDENCI"); while (rs.next()) { // pętla trwa dopóki istnieje kolejny rekord // przetworzenie rekordu } Przetwarzanie obiektu ResultSet – cd. Obiekt ResultSet posiada metody pozwalające odczytywać pola bieżącego rekordu jako różne typy (int getInt(), String getString(), Date getDate() etc.) Pola można adresować nazwą pola ResultSet rs = stm.executeQuery( "SELECT ID, IMIE, NAZWISKO FROM STUDENCI"); while (rs.next()) { String id = rs.getInt("ID"); String imie = rs.getString("IMIE"); String nazwisko = rs.getString("NAZWISKO"); } Przetwarzanie obiektu ResultSet – cd. ...lub indeksem pola w zapytaniu ResultSet rs = stm.executeQuery( "SELECT ID, IMIE, NAZWISKO FROM STUDENCI"); while (rs.next()) { String id = rs.getInt(1); String imie = rs.getString(2); String nazwisko = rs.getString(3); } Zamknięcie otwartych obiektów Wszystkie otwarte obiekty rezerwują zasoby, dlatego warto zamykać je po wykorzystaniu Wszystkie obiekty Connection, Statement i ResultSet posiadają metodę close() rs.close(); stm.close(); conn.close(); Cały przykład public class StudenciDB { public static void main(String[] args) throws SQLException { Class.forName("org.hsqldb.jdbcDriver"); Connection conn = DriverManager("jdbc:hsqldb:hsql://localhost/", "sa", ""); Statement stm = conn.createStatement(); ResultSet rs = stm.executeQuery( "SELECT ID, IMIE, NAZWISKO FROM STUDENCI"); while (rs.next()) { System.out.println("Imie: " + rs.getString(2) + ", nazwisko: " + rs.getString(3)); } rs.close(); stm.close(); conn.close(); } } Transakcje Transakcje modyfikujące bazę danych muszą zostać zatwierdzone lub anulowane Służą do tego metody commit() i rollback() w klasie Connection conn.commit(); // zatwierdzenie conn.rollback(); // anulowanie Aby nie zapomnieć o zatwierdzeniu transakcji można ustawić automatyczne zatwierdzanie conn.setAutoCommit(true); Obsługa transakcji złożonych Transakcje składające się z wielu poleceń SQL mogą być wykonywane w jednym bloku try { conn.setAutoCommit(false); pstm.executeUpdate(sql1); pstm.executeUpdate(sql2); conn.commit(); // zatwierdzenie operacji } catch (SQLException ex) { System.out.println("Nie udało się..."); conn.rollback(); // anulowanie operacji } finally { conn.close(); } Wydajność JDBC Wydajność JDBC może w wielu przypadkach być niewystarczająca. Aby poprawić wydajność realizacji transakcji przez JDBC, można: zastosować mechanizm puli połączeń do bazy danych, dzięki czemu połączenia nie są tworzone i zamykane, a pobierane i zwracane do puli stosować obiekt PreparedStatement zamiast Statement wykonywać wiele operacji SQL w jednej transakcji z wywołaniem commit() na końcu Obsługa wyjątków Niemal każda operacja JDBC może spowodować zgłoszenie wyjątku SQLException Nieobsłużenie wyjątku może spowodować porzucenie otwartego połączenia do bazy danych try { // wykonujemy różne operacje JDBC } catch (SQLException ex) { System.out.println(ex); } finally { if (conn != null) // próba zamknięcia połączenia try { conn.close(); } catch (SQLException ex2) {} } Q&A