Zakład Inżynierii Oprogramowania
Transkrypt
Zakład Inżynierii Oprogramowania
Zakład Inżynierii Oprogramowania Programowanie w języku Java WYKŁAD dr inż. Piotr Zabawa Certyfikowany Konsultant IBM/Rational e-mail: [email protected] www: http://www.pk.edu.pl/~pzabawa 14.04.2014 Zakład Inżynierii Oprogramowania WYKŁAD 8 Trwałość w Java – cz. 1 Wykład w zakresie JDBC został w znacznej mierze oparty o źródła, których autorem jest Jakob Jenkov dr inż. Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java Celem wykładów poświęconych trwałości w Java nie jest wprowadzenie w zagadnienia relacyjnych baz danych ani w język SQL. Te zagadnienia zostaną opanowane przez studentów w ramach przedmiotów poświęconych bazom danych. Wykład został podzielony na dwie części: • JDBC – standard wymagający znajomości SQL • JPA – standard pozwalający uniknąć znajomości SQL Pierwsza część może okazać się przydatna osobom pragnącym tą drogą poznać SQL. Druga część pozwala uniknąć znajomości SQL osobom, które przywiązują większą wagę do tworzonego przez nich oprogramowania niż do samej kwestii składowania danych. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java Wprawdzie relacyjne bazy danych są relatywnie starą technologią, to jednak nadal dominują na rynku. Było wiele prób zastąpienia ich kolejno przez obiektowe, obiektowo-relacyjne, XML’owe, a obecnie przez NoSQL’owe bazy danych. Ale jak dotąd, żadna z propozycji nie odniosła sukcesu. Dlatego właśnie dominują obecnie relacyjne bazy danych. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java W ramach języka Java trwałość można zapewnić na wiele sposobów: • Wprost w Java SE – JDBC (Java Database Connectivity) – odpowiednik ODBC • Z wykorzystaniem frameworków – JPA2 (Java Persistence API) – standard wykorzystany np. w • Hibernate • EclipseLink • TopLink – EJB3 (Enterprise Java Beans) – framework wspierający m.in. trwałość – Spring Data (Spring Data JPA, Spring Data JDBC Extensions) – Seam dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java Java posiada wsparcie do obsługi trwałości nie tylko w zakresie relacyjnych baz danych, lecz również NoSQL’owych baz danych zyskujących stopniowo na znaczeniu. Dobrym narzędziem jest projekt Spring Data zawierający szereg podprojektów dedykowanych do różnych rodzajów baz danych i wprowadzających ujednolicenie do wszystkich podejść za pomocą podprojektu Spring Data Commons. Jednak na zajęciach skoncentrujemy się jedynie na zagadnieniu mapowania obiektowo-relacyjnego, czyli ORM (Object-Relational Mapping), a więc na dostępie do relacyjnych baz danych. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java Interesować nas będą jedynie dwa z wymienionych wyżej podejść: • JDBC – niskopoziomowe działanie bliskie SQL, ale za to znaczna kontrola nad implementacją warstwy trwałości • JPA2/Hibernate – programowanie wysokopoziomowe z możliwością niskopoziomowej optymalizacji, narzędzia forward- i reverseengineering, XML ze strukturą bazy danych Warto mieć na uwadze, że frameworki wprowadzają swoje wysokopoziomowe języki zapytań, zwane ogólnie EL (Expression Languages). Są też dodatkowe języki związane z przeprowadzaniem operacji na relacyjnych bazach danych, np. DDL (Data Definition Language) wykorzystywany m.in. z poziomu narzędzi modelowania w UML do generowania struktury bazy danych z modelu. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java Dawniej wykorzystywany był cały szereg rozwiązań wspierających dostęp do relacyjnych baz danych, jednak z czasem rozwiązania o mniejszym znaczeniu zostały zapomniane lub wchłonięte przez inne rozwiązania. Dobrym przykładem jest standard JPA, który scalił ze sobą rozwiązania takie jak EJB 2 CMP, JDO (nie odniósł sukcesu wśród dostawców frameworków Java EE, ale trafił do standardu), Hibernate oraz TopLink API. Należy również mieć na względzie, że dostępne frameworki nie są tylko implementacją standardów. Dany framework na ogół: • Stanowi realizację dużej części, ale nie całości standardu • Proponuje własne rozwiązania wykraczające poza standard, a pozwalające na konkurowanie z innymi implementacjami standardu. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java Znaczenie wzorców korporacyjnych w dostępie do danych. Istotną rolę odgrywają następujące architektoniczne wzorce korporacyjne: • DAO (Data Access Object) • DTO (Data Transfer Object) • Active Record • Broker • SDO = JDO + DTO (Service Data Object = Java Data Object + Data Transfer Object) dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java Wartym zainteresowania w kontekście trwałości jest wzorzec architektoniczny DAO (Data Access Object), który zostanie również omówiony ze względu na jego duże znaczenie praktyczne. Wzorzec ten wprowadza dodatkową warstwę (dlatego jest architektoniczny a nie projektowy) do systemu softwerowego. Rzutuje to wprawdzie negatywnie na efektywność operacji na danych, ale nie zawsze ona jest najważniejsza. Wzorzec ten uniezależnia dodatkowo warstwę logiki biznesowej od warstwy danych, co ułatwia wprowadzanie zmian. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java Trudno jednoznacznie przesądzić które z podejść (ORM lub JDBC) jest lepsze. Są zwolennicy jednego lub drugiego, zwolennicy poszczególnych standardów lub narzędzi. Są również tacy, którzy nie wierzą w ORM a nawet w obiektowość i preferują JDBC. Są też tacy, którzy za jedyną słuszną drogę uważają obiektowe bazy danych. Wydaje się jednak, że właściwym podejściem jest stosowanie takiego podejścia, które odpowiada danej osobie. Większym problemem jest dokonanie wyboru dla przedsiębiorstwa wytwarzającego oprogramowanie. Jednak na pewno warto przekonać się o zaletach zarówno jednego jak i drugiego podejścia. W przeciwnym razie trudno podjąć odpowiednią decyzję. Dalej podane zostały argumenty za używaniem (lub nieużywaniem) JPA i ORM. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania JDBC dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC JDBC API jest interfejsem programowym zapewniającym dostęp do relacyjnej bazy danych z poziomu języka Java w sposób niemal niezależny od serwera bazy danych. Stanowi więc mechanizm abstrakcji, którego realizacją są konkretne serwery bazodanowe. Standaryzuje ono następujące operacje: • Nawiązanie połączenia z bazą danych • Wykonanie zapytań na bazie danych • Nawigację po wynikach zapytania • Modyfikowanie danych w bazie Standaryzacji nie podlega jednak sam język zapytań SQL – jest on różny dla różnych serwerów baz danych. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC JDBC zapewnia dostęp niskopoziomowy do bazy danych umożliwiając programiście posługiwanie się językiem zapytań SQL. Język ten zaliczany jest do paradygmatów deklaratywnych oprogramowania. Jego wyrażenia określają cel a nie sposób dojścia do niego. Poszczególni dostawcy serwerów bazodanowych konkurują między sobą m.in. zapewniając zróżnicowane wersje języka SQL. Zatem wykorzystanie standardu JDBC pozwala skorzystać programiście Java w pełni z oferty producentów tych serwerów. Jednak niskopoziomowe operacje mogą być niewygodne w użyciu. Dlatego w kolejnym wykładzie zostaną zaprezentowane inne rozwiązania. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC • • Pakiety standardowej biblioteki Java zawierające JDBC: java.sql javax.sql dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC • • • • Struktura JDBC API: Sterowniki JDBC (JDBC Drivers) Połączenia (Connections) Stwierdzenia (Statements) Zbiory wyników (Result Sets) • • • • Podstawowe scenariusze użycia JDBC API: Zapytania kierowane do bazy danych (odczyt danych) Zapytania do bazy danych o meta-dane Update bazy danych Wykonywanie transakcji dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC JDBC Drivers Zadaniem tych elementów standardu JDBC jest implementacja interfejsów JDBC. Implementacja ta zależy od serwera bazy danych. Jednak interfejsy są od niego niezależne. Można więc podmienić sterownik (podmienić serwer bazy danych) nie zmieniając kodu aplikacji – w sytuacji idealnej, ze względu na różnice w funkcjonalności i w SQL. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Connections Po zainicjowaniu drivera umożliwiają one nawiązanie jednego lub więcej połączeń z bazą danych poprzez serwer bazodanowy. Całą komunikacja aplikacji w Java z bazą danych przebiega wyłącznie poprzez Connections. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Statements Stwierdzenia służą do wykonywania zapytań o dane i wprowadzania zmian do danych w bazie. Istnieje kilka różnych stwierdzeń pozwalających na wykonywanie różnych zapytań. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Result Sets W wyniku wykonania zapytania można uzyskać jego wynik w postaci ResultSet. Klasa ta umożliwia nawigowanie po jej obiektach w celu uzyskania wyników zapytania z poziomu języka Java, a więc w sposób obiektowy. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Podstawowe scenariusze • • • • Zapytania kierowane do bazy danych – noszą one nazwę zapytań (query) i polegają wyłącznie na odczycie danych z bazy. Są najczęściej używanymi operacjami. Zapytania do bazy danych o meta-dane – polegają na uzyskaniu od bazy danych informacji o jej strukturze (tabelach, kolumnach, typach danych, relacjach); są relacyjno-bazo-danowym odpowiednikiem klasowoobiektowego mechanizmu refleksji dostępnego w Java Update bazy danych – operacje te polegają na zapisie do bazy danych; zapis może dotyczyć wstawiania nowych rekordów lub modyfikowania istniejących Wykonywanie transakcji – polega na łącznym wykonywaniu wielu operacji na bazie danych z jednoczesną gwarancją wykonania ich wszystkich (sukces) lub niewykonania żadnej z nich (porażka) dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania źródło: Jakob Jenkov dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC • • • • Typy sterowników JDBC JDBC-ODBC bridge driver – wsparcie usunięte w Java 8! Java + Native code driver All Java + Middleware translation driver All Java driver – jest to jedyny obecnie wspierany typ sterownika. Łączy aplikację bezpośrednio z bazą danych i jest specyficzny dla poszczególnych serwerów. Jest też najbardziej efektywnym (performance) rodzajem sterownika. źródło: Jakob Jenkov dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Dalej zostały omówione typowe kroki spotykane w aplikacjach wykorzystujących JDBC. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Załadowanie sterownika (od Java 6 automatycznie!) Należy je wykonać raz. Przykładowy kod: Class.forName("com.mysql.jdbc.Driver"); Korzystamy z mechanizmu refleksji ładując poprzez standardowego class loader’a klasę sterownika określoną przez nazwę. Klasa ta zależy od serwera bazy danych. Powyższy przykład ładuje sterownik JDBC serwera MySQL. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Otwarcie połączenia z bazą danych Wykorzystujemy klasę java.sql.DriverManager. Przykład dla MySQL: String url = "jdbc:mysql://[host]:[port]/db_name"; String user = „uname"; String password = „passwd"; Connection connection = DriverManager.getConnection(url, user, password); [host] - jeśli pominięty, to localhost [port] - domyślny port dla serwera MySQL, to 3306 dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Jawne zamknięcie połączenia Jeśli nie zamierzamy już korzystać z danego połączenia z bazą danych, to powinniśmy je zamknąć w celu zwolnienia zasobów. Możemy to wykonać za pomocą metody: connection.close(); dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Zapytania o dane (odczyt) Jeśli mamy otwarte połączenie z bazą danych możemy skierować do niej zapytanie w następujący sposób: Statement statement = connection.createStatement(); String sql = "select * from people"; ResultSet result = statement.executeQuery(sql); Wyniki zapytania zostają umieszczone w klasie ResultSet, którą możemy iterować wierszami (rekordami): while(result.next()) { String name = result.getString("name"); long age = result.getLong ("age"); } dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Dla danego wiersza można uzyskać dostęp do danych w kolumnie za pomocą jednej z metod: getX() gdzie: X – klasa wrapera typu prostego Dostęp do poszczególnych kolumn tabeli może być za pomocą nazwy kolumny lub indeksu kolumny, co pokazano poniżej. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC getString(<column_name>); getLong(<column_name>); getInt(<column_name>); getDouble(<column_name>); getBigDecimal(<column_name>); dr inż..Piotr Zabawa Instytut Informatyki getString(<column_index>); getLong(<column_index>); getInt(<column_index>); getDouble(<column_index>); getBigDecimal(<column_index>); Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Indeks kolumny w ramach ResultSet można uzyskać po nazwie za pomocą wywołania następującej metody: int columnIndex = result.findColumn("columnName"); Dostęp za pomocą indeksu jest szybszy. Po skorzystaniu z wyników zapytania należy zwolnić zasoby: result.close(); statement.close(); Można wywołania te umieścić w bloku finally. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC try(Statement statement = connection.createStatement()) { String sql = "select * from people"; try(ResultSet result = statement.executeQuery(sql)) { ResultSet result = statement.executeQuery(sql); while(result.next()) { String name = result.getString("name"); long age = result.getLong("age"); System.out.println(name); System.out.println(age); } } } dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Zapis do bazy Są dwa rodzaje zapisów: • Aktualizacja rekordu • Usunięcie rekordu Do wykonania obu rodzajów zapisu wykorzystywana jest metoda: executeUpdate() dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Zmiana rekordów Statement statement = connection.createStatement(); String sql = "update people set name='John' where id=123"; int rowsAffected = statement.executeUpdate(sql); Metoda executeUpdate() zwraca informację o ilości zmienionych rekordów. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Usunięcie rekordów Statement statement = connection.createStatement(); String sql = "delete from people where id=123"; int rowsAffected = statement.executeUpdate(sql); Metoda executeUpdate() zwraca informację o ilości zmienionych rekordów. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC ResultSet Klasa ResultSet zawiera wynik zapytania. Można go sobie wyobrazić jako tabelę z rekordami w wierszach i polami rekordów w kolumnach. Należy pamiętać, że komórki tabeli mogą zawierać dane, a niektóre wartość null reprezentująca brak danych (nie wszystkie pola w tabeli relacyjnej bazy danych są wymagane). Należy mieć na uwadze fakt, że nie można uzyskać w sposób bezpośredni informacji o ilości wierszy w ResultSet. • Są dwa sposoby utworzenia obiektu tej klasy: Przez wykonanie zapytania (Statement) • Przez wykonanie przygotowanego zapytania (PreparedStatement) dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Wykonanie Statement: Statement statement = connection.createStatement(); ResultSet result = statement.executeQuery("select * from people"); Wykonanie PreparedStatement: String sql = "select * from people"; PreparedStatement statement = connection.prepareStatement(sql); ResultSet result = statement.executeQuery(); dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC W czasie tworzenia stwierdzenia możemy sterować następującymi parametrami tworzonego przez niego obiektu klasy ResultSet: • • • Type Concurrency Holdability Statement statement = connection.createStatement( ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_OVER_COMMIT ); PreparedStatement statement = connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_OVER_COMMIT ); dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Typy ResultSet • ResultSet.TYPE_FORWARD_ONLY Oznacza, że nie jest możliwe iterowanie w przeciwnym kierunku niż od pierwszego do ostatniego rekordu. Jest domyślny. • ResultSet.TYPE_SCROLL_INSENSITIVE Można iterować w dowolnym kierunku i przeskakiwać do dowolnego rekordu, ale zmiana danych w bazie danych nie zostanie odzwierciedlona w obiekcie klasy ResultSet po jego utworzeniu. • ResultSet.TYPE_SCROLL_SENSITIVE Można iterować w dowolnym kierunku i przeskakiwać do dowolnego rekordu. Zmiana danych w bazie danych zostanie odzwierciedlona w obiekcie klasy ResultSet po jego utworzeniu. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Metody nawigacji Dostępność poniżej przedstawionych metod zależy od serwera bazy danych, sterownika JDBC oraz typu ResultSet. Metoda Opis absolute() Ustawia kursor we wskazanej pozycji względem początkowego rekordu afterLast() Ustawia kursor na końcu (poza zakresem) beforeFirst() Ustawia kursor na początku (poza zakresem) first() Ustawia kursor na pierwszy rekord last() Ustawia kursor na ostatni rekord next() Przesuwa kursor do następnej pozycji previous() Przesuwa kursor do poprzedniej pozycji relative() Przesuwa kursor z aktualnej pozycji o wskazaną ilość rekordów (+/-) dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Metody uzyskiwania informacji o aktualnej pozycji kursora Metoda Opis getRow() Zwraca numer wiersza dla aktualnej pozycji kursora getType() Zwraca informację o typie ResultSet isAfterLast() Zwraca true jeśli kursor wyszedł poza ostatni rekord isBeforeFirst() Zwraca true jeśli kursor jest przed pierwszym rekordem isFirst() Zwraca true jeśli kursor wskazuje na pierwszy rekord dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Metoda odświeżająca aktualny wiersz w ResultSet, jeśli ResultSet jest typu ResultSet.TYPE_SCROLL_SENSITIVE Metoda Opis refreshRow() Aktualizuje wartości pól rekordu w ResultSet na podstawie aktualnych wartości rekordu w bazie danych dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Współbieżność ResultSet Dostępne są dwa poziomy współbieżności: • ResultSet.CONCUR_READ_ONLY • ResultSet.CONCUR_UPDATABLE Jeśli ResultSet jest określony jako , to można dokonać aktualizacji poszczególnych pól danego rekordu za pomocą metod updateX() analogicznych do getX(). Do pól można odwoływać się po nazwie lub po indeksie kolumny. Należy pamiętać o wywołaniu metody result.updateRow() dla całego rekordu po aktualizacji jego pól. Metoda ta dokonuje aktualizacji danych w bazie pod warunkiem, że nie została wywołana wewnątrz transakcji. Przykłady metod updateX() podano poniżej. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC updateString(<column_name>); updateLong(<column_name>); updateInt(<column_name>); updateDouble(<column_name>); updateBigDecimal(<column_name>); dr inż..Piotr Zabawa Instytut Informatyki updateString(<column_index>); updateLong(<column_index>); updateInt(<column_index>); updateDouble(<column_index>); updateBigDecimal(<column_index>); Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Wstawianie wierszy do ResultSet Aby wstawić wiersz do ResultSet należy wykonać następujące kroki: • Wywołać ResultSet.moveToInsertRow() • • Zaktualizować wartości kolumn w tym wierszu Wywołać ResultSet.insertRow() dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC ResultSet Holdability Cecha ta określa czy po dokonaniu commitu obiektu ResultSet do bazy danych następuje destrukcja obiektu ResultSet czy nie. Dostępność tej funkcjonalności dla danego sterownika można sprawdzić wywołaniem metody: DatabaseMetaData.supportsResultSetHoldability(int holdability) • • Rodzaje holdability: ResultSet.CLOSE_CURSORS_OVER_COMMIT ResultSet.HOLD_CURSORS_OVER_COMMIT dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC • • • • PreparedStatement Powody stosowania: Łatwość wprowadzania parametrów do zapytania SQL Łatwość ponownego użycia z nowymi parametrami Możliwość zwiększenia wydajności wykonywanych komend Ułatwienie wykonywania batch updates. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Przykład: String sql = "update people set firstname=? , lastname=? where id=?"; PreparedStatement preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1, "Gary"); preparedStatement.setString(2, "Larson"); preparedStatement.setLong (3, 123); int rowsAffected = preparedStatement.executeUpdate(); dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Zwiększenie efektywności zapytań: • Poprzez cache’owanie zapytań po stronie sterownika • Poprzez współdzielenie zapytań pomiędzy aplikacjami Java • Poprzez cache’owanie zapytań po stronie serwera bazy danych – zwiększenie wydajności poprzez minimalizację analizy planu wykonania zapytań dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Batch Updates Ten tryb pracy z bazą danych polega na przesyłaniu do niej wielu komend za jednym razem. Nie ma sensu stosowanie go dla zapytań (odczytu), lecz jedynie dla zapisu. Można wykonywać takie update’y za pomocą: • Statement • PreparedStatement dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Statement Statement statement = null; try{ statement = connection.createStatement(); statement.addBatch("update people set firstname='John' where id=123"); statement.addBatch("update people set firstname='Eric' where id=456"); statement.addBatch("update people set firstname='May' where id=789"); int[] recordsAffected = statement.executeBatch(); } finally { if(statement != null) statement.close(); } dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC PreparedStetment String sql = "update people set firstname=? , lastname=? where id=?"; PreparedStatement preparedStatement = null; try{ preparedStatement = connection.prepareStatement(sql); preparedStatement.setString(1, "Gary"); preparedStatement.setString(2, "Larson"); preparedStatement.setLong (3, 123); preparedStatement.addBatch(); preparedStatement.setString(1, "Stan"); preparedStatement.setString(2, "Lee"); preparedStatement.setLong (3, 456); preparedStatement.addBatch(); int[] affectedRecords = preparedStatement.executeBatch(); } finally { if(preparedStatement != null) preparedStatement.close(); } dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Ryzyko stosowania batch updates polega na tym, że część komend może się udać, a część nie i wtedy nie wiadomo jak postąpić w kodzie. Dlatego dobrą praktyką wykonywania batch updates jest wykonywanie ich w ramach transakcji. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Transakcje Służą określeniu, który zestaw operacji ma być traktowany łącznie jako operacja atomowa. Jeśli wszystkie operacje składowe zakończą się sukcesem, to zestaw operacji zostanie wykonany w całości. Jeśli któraś z operacji składowych nie powiedzie się, to nie zostanie wykonana żadna z operacji. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Przykład transakcji Connection connection = ... try { connection.setAutoCommit(false); // create and execute statements etc. connection.commit(); } catch(Exception e) { connection.rollback(); } finally { if(connection != null) connection.close(); } dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Procedury składowane Jest to rozwiązanie dostępne po stronie bazy danych. Służy do przechowywania procedur zawierających komendy w celu zwiększenia wydajności. Utworzenie komendy: CallableStatement callableStatement = connection.prepareCall("{call calculateStatistics(?, ?)}"); albo CallableStatement callableStatement = connection.prepareCall("{call calculateStatistics(?, ?)}", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, ResultSet.CLOSE_CURSORS_OVER_COMMIT ); dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Java 7 • Dodano instrukcję try-with-resources w celu zautomatyzowania zamykania zasobów znanego z wykładu dotyczącego wyjątków – przykład z zamykaniem strumieni. Połączenie z bazą danych traktowane jest jako zasób. Przykład na następnym slajdzie • Dodano interfejs RowSetFactory i klasę RowSetProvider pozwalające na uzyskanie każdego z rodzajów RowSet dostępnych dla danego JDBC Driver, a więc uwzględniających specyfikę serwera bazy danych. Przykład na kolejnym slajdzie dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Przykład: public static void sampleQueryProc(Connection sampleCon) throws SQLException { String sampleQuery = "select ROLLNO, NAME, ADDRESS from STUDENT"; try (Statement sampleStmt = sampleCon.createStatement()) { ResultSet sampleResultSet = sampleStmt.executeQuery(sampleQuery); while (rs.next()) { int rollNo = sampleResultSet.getInt("ROLLNO"); String studentName = sampleResultSet.getString("NAME"); String studentAddress = sampleResultSet.getString("ADDRESS"); System.out.println(“ROLLNO:” + rollNo + " NAME: " + studentName + " ADDRESS: " + studentAddress); } } } dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC public void sampleMethod(String sampleUserName, String samplePassword) throws SQLException { RowSetFactory sampleRowSetFactory = null; JdbcRowSet sampleRowSet = null; try { sampleRowSetFactory = RowSetProvider.newFactory(); sampleRowSet = sampleRowSetFactory.createJdbcRowSet(); sampleRowSet.setUrl("jdbc:sampleDriver:sampleAttribute"); sampleRowSet.setUsername(sampleUserName); sampleRowSet.setPassword(samplePassword); sampleRowSet.setCommand(""select ROLLNO, NAME, ADDRESS from STUDENT"); sampleRowSet.execute(); } catch(Exception e) { } } dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Parametry wyjściowe z procedury składowanej Procedura składowana może zwracać wartości. Przykład korzystania z parametrów wyjściowych procedury składowanej podano na następnym slajdzie. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC CallableStatement callableStatement = connection.prepareCall("{call calculateStatistics(?, ?)}"); callableStatement.setString(1, "param1"); callableStatement.setInt (2, 123); callableStatement.registerOutParameter(1, java.sql.Types.VARCHAR); callableStatement.registerOutParameter(2, java.sql.Types.INTEGER); ResultSet result = callableStatement.executeQuery(); // najpierw ResultSet while(result.next()) { ... } // potem OUT parameters String out1 = callableStatement.getString(1); int out2 = callableStatement.getInt (2); dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Należy najpierw analizować ResultSet, a dopiero potem parametry wyjściowe – dobra praktyka związana z kompatybilnością z różnymi serwerami bazodanowymi. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC DatabaseMetaData Metody z tej grupy służą uzyskaniu ogólnych informacji o bazie danych. Uzyskanie obiektu meta-danych: DatabaseMetaData databaseMetaData = connection.getMetaData(); Uzyskanie danych o serwerze bazodanowym: int majorVersion = databaseMetaData.getDatabaseMajorVersion(); int minorVersion = databaseMetaData.getDatabaseMinorVersion(); String productName = databaseMetaData.getDatabaseProductName(); String productVersion = databaseMetaData.getDatabaseProductVersion(); Uzyskanie danych o sterowniku: int driverMajorVersion = databaseMetaData.getDriverMajorVersion(); int driverMinorVersion = databaseMetaData.getDriverMinorVersion(); dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Wylistowanie tabel: String catalog = null; String schemaPattern = null; String tableNamePattern = null; String[] types = null; ResultSet result = databaseMetaData.getTables( catalog, schemaPattern, tableNamePattern, types ); while(result.next()) { String tableName = result.getString(3); } Wylistowanie kolumn w tabeli: String catalog = null; String schemaPattern = null; String tableNamePattern = "my_table"; String columnNamePattern = null; ResultSet result = databaseMetaData.getColumns( catalog, schemaPattern, tableNamePattern, columnNamePattern); while(result.next()){ String columnName = result.getString(4); int columnType = result.getInt(5); } dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Uzyskanie informacji o kluczu prywatnym tabeli String catalog = null; String schema = null; String tableName = "my_table"; ResultSet result = databaseMetaData.getPrimaryKeys( catalog, schema, tableName); while(result.next()) String columnName = result.getString(4); Dla kluczy złożonych zwrócony ResultSet może mieć wiele wierszy. dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Sprawdzanie jakie funkcjonalności są wspierane przez dany sterownik databaseMetaData.supportsGetGeneratedKeys(); databaseMetaData.supportsGroupBy(); databaseMetaData.supportsOuterJoins(); dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java - JDBC Ustawianie wartości parametrów wywołania metody składowanej: callableStatement.setString(1, "param1"); callableStatement.setInt (2, 123); Wykonanie metody składowanej: ResultSet result = callableStatement.executeQuery(); albo callableStatement.executeUpdate(); dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Trwałość w Java – 10 dobrych praktyk JDBC • • • • • • • • • • Stosować PreparedStatement Stosować ConnectionPool Wyłączać tryb auto commit Stosować JDBC Batch Update W dostępie do ResultSet stosować nazwy kolumn aby uniknąć wyjątku invalidColumIndexError Stosować zmienne Bind zamiast konkatenacji String’ów Zawsze zamykać Statement, PreparedStatement i Connection Wybierać odpowiedni sterownik JDBC dla tworzonej aplikacji Stosować standardowe zapytania i unikać stosowania wyrażeń specyficznych dla serwera bazy danych o ile to możliwe Stosować właściwą metodę getXXX() dr inż..Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki Zakład Inżynierii Oprogramowania Koniec dr inż. Piotr Zabawa Instytut Informatyki Wydział Fizyki, Matematyki i Informatyki