Pobierz prezentację
Pobieranie prezentacji. Proszę czekać
OpublikowałMariusz Miśko Został zmieniony 11 lat temu
1
Sterownik JDBC i obsługa relacyjnych baz danych w Javie
Mariusz Czarneki, Marcin Walewski
2
JDBC Profesjonalne systemy bazodanowe udostępniają interfejsy programistyczne (API), dzięki którym można uzyskiwać dostęp do baz danych. Interfejsy takie są zdefiniowane dla różnych popularnych języków programowania na różne platformy systemowe. Programistyczny interfejs dostępu do baz danych z poziomu Javy to JDBC (ang. Java Database Connectivity API). JDBC jest uniwersalny i nie zależny od: maszyny bazodanowej, platformy sprzętowej, systemu operacyjnego.
3
JDBC (2) JDBC to zestaw klas i interfejsów umieszczonych w pakiecie java.sql, który umożliwia: połączenie z relacyjną bazą danych, wykonywanie instrukcji SQL na bazie, przetwarzanie wyników instrukcji SQL (w tym tabel wynikowych). Zadaniem JDBC jest ukrycie przed programistą wszelkich specyficznych właściwości określonej bazy danych. Najnowsza wersja JDBC to 4.1.
4
Przykładowe architektury JDBC
Architektura dwuwarstwowa Architektura trójwarstwowa Przeglądarka Maszyna klienta (GUI) Aplikacja Java JDBC Maszyna klienta HTML, RMI, CORBA, Web Services Serwer Aplikacyjny Java JDBC Maszyna z logiką biznesową Właściwy protokół DBMS Właściwy protokół DBMS Serwer bazodanowy Serwer bazodanowy
5
Struktura JDBC java.sql.Driver to interfejs odpowiedzialny za nawiązanie połączenia z bazą danych oraz za tłumaczenie zapytań SQLowych na język określonej bazy. java.sql.DriverManager to klasa, która odpowiada za zarządzanie listą dostępnych sterowników do baz danych i udostępnienie aplikacji tego jednego, który jest przez nią wymagany. java.sql.Connection to interfejs, który reprezentuje pojedynczą transakcję bazodanową. java.sql.Statement jest to interfejs reprezentujący zapytanie SQLowe. java.sql.ResultSet to interfejs reprezentujący zbiór rekordów, będących wynikiem zapytania SQLowego; wynik zapytania znajduje się po stronie bazy danych.
6
4 typy sterowników TYP 1 – sterowniki, które implementują JDBC API mapując do innego API bazodanowego np. ODBC. Sterowniki te są zależne od bibliotek natywnych, które ograniczają przenośność. Przykładem jest JDBC-ODBC Bridge. TYP 2 – sterowniki pisane są częściowo w Javie z kodem natywnym. Te sterowniki wykorzystują natywne biblioteki klienta specyficzne dla danego źródła danych. Z powodu natywnego kodu przenośność ograniczona. TYP 3 – sterowniki napisane w pełni w Javie, które komunikują się przez warstwę pośredniczącą z serwerem korzystając z niezależnych od bazy danych protokołów. TYP 4 – sterowniki, które napisane są w pełni w Javie i implementują specyficzny dla danej bazy danych protokół. Klient łączy się bezpośrednio ze źródłem danych.
7
Pliki JAR zawierające sterownik do RDBMS
Program w javie musi zarejestrować klasę sterownika JDBC. Automatyczna rejestracja jest wymagana dla sterowników zgodnych z JDBC4. W starszych wersjach trzeba ręcznie dokonać rejestracji: poprzez załadownie sterownika do pamięci: Class.forName(”org.postgresql.Driver”); albo przez skonfigurowanie właściwości jdbc.drivers przy uruchamianiu programu: java –Djdbc.drivers=org.postgresql.Driver Program sama aplikacja też może skonfigurować tą właściwość: System.setProperty(”jdbc.drivers”, ”org.postgresql.Driver”);
8
Ustanowienie połączenia ze źródłem danych
Do połączenia z bazą danych wykorzystywane są dwa mechanizmy: DriverManager – wymaga, aby aplikacja załadowała odpowiedni sterownik JDBC korzystając z umieszczonego na stałe w kodzie adresu URL. Początkowo próbuje załadować sterownik wyszczególniony w property jdbc.drivers. DataSource – interfejs wykorzystywany przez DriverManager pozwalający zapewnić przeźroczystość źródła danych dla aplikacji. DataSource reprezentuje szczególne źródło danych.
9
Ustanowienie połączenia z źródłem danych – DriverManager
Załadowanie sterowników. Class.forName("org.apache.derby.jdbc.XXXXDriver"); Class.forName – tworzy instancję sterowników XXXX (np. Oracle) i rejestruje je w DriverManager Korzystanie z DriverManager Zadaniem DriverManager jest rozpoznanie na podstawie URL rodzaju sterownika oraz jego odnalezieniu. jdbc:XXXX:<NazwaBazyDanych>[lista_wlasciwosci] Connection conn = DriverManager.getConnection("jdbc:XXXX:BazaDanych", login, pass); Połączenie z bazą należy na końcu zamknąć: try { if (conn!=null) conn.close(); } catch (SQLException ex) {/*…*/}
10
URL dla bazy danych URL dla bazy danych umożliwia identyfikację bazy, załadowanie odpowiedniego sterownika i uzyskanie połączenia z bazą. Składnia URLa używanego w JDBC: jdbc:<subprtokół>:<subnazwa> gdzie <subprtokół> to nazwa sterownika lub mechanizmu obsługi połączenia z bazą danych, a <subnazwa> to identyfikator bazy danych.
11
URL dla bazy danych (2) Przykład URLa dla połączenia z bazą zarejesrtowaną w ODBC: jdbc:odbc:moja_baza Przykłady URLi dla różnych systemów bazodanowych: MySQL: jdbc:mysql://localhost:3306/mydb MS-SQL: jdbc:sqlserver:// :1433/mydb PostgreSQL: jdbc:postgresql://serv:5432/mydb Mini-SQL: jdbc:msql://dbserver:1234/mydb Oracle: Java-DB: jdbc:derby:newdb;create=true
12
Ustanawianie połączenia przez DataSource
DataSource zwiększa przenaszalność aplikacji, gdyż aplikacja korzysta wyłączenie z nazwy źródła, bez wnikania w jego rodzaj. InitialContext ic = new InitialContext(); DataSource ds = ic.lookup("java:comp/env/jdbc/myDB"); Connection con = ds.getConnection(); DataSource ds = (DataSource) org.apache.derby.jdbc.ClientDataSource() ds.setPort(1527); ds.setHost("localhost"); ds.setUser("APP"); ds.setPassword("APP");
13
Metainformacje o bazie danych
Metainformacje o bazie danych uzyskujemy za pomocą metody getMetaData: DatabaseMetaData md = conn.getMetaData(); W obiekcie DatabaseMetaData mamy cały zbiór metod do wyciągania informacji o bazie danych: getDatabaseProductName () getDriverName () getURL () getUserName () supportsTransactions () i wiele innych
14
Wyjątki SQL Często zdarza się, że jakaś operacja na bazie danych zakończy się niepowodzeniem – wtedy zgłaszany jest wyjątek: SQLException. Wyjątki te sygnalizują błędy, wykrywane albo przez sam sterownik (np. brak jakiegoś trybu działania), albo przez system bazodanowy (np. błędy składniowe w SQL lub próba naruszenia ograniczeń jednoznaczności czy spójności referencyjnej itp.) Wyjątki MUSIMY obsługiwać. W czasie operacji na bazie może zostać zgłoszonych kilka wyjątków – wyjątek SQLException potrafi się kolejkować.
15
Wyjątki SQL (2) Łapanie wyjątku SQLException na przykładzie:
try { // operacje na bazie danych } catch (SQLException ex) { do { System.err.println(ex.getMessage()); } while ((ex=ex.getNextException())!=null); } Czasami pojawiają się tylko ostrzeżenia w postaci wyjątków SQLWarning dziedziczących po SQLException.
16
Czas na przykład = „ConnectionTest”
17
Wykonywanie zapytań do bazy – obiekt Statement
Do wykonywania instrukcji SQL służy obiekt typu Statement, a także obiekty typu interfejsów pochodnych: PreparedStatement (prekompilowane instrukcje SQL), CallableStatement (przechowywane procedury). Obiektów tych nie tworzymy bezpośrednio, tylko uzyskujemy je od obiektu Connection za pomocą odwołań (odpowiednio): createStatement(…), prepareStatement(…), prepareCall(…). Statement stm = conn.createStatement(); Aby wykonać konkretne polecenie SQL, na rzecz obiektu typu Statement wywołujemy odpowiednie metody z argumentem typu String, kttóry jest poleceniem SQL.
18
Wykonywanie zapytań do bazy – obiekt Statement (2)
Metody na rzecz obiektu Statement : stm.executeQuery(…); dla zapytania SELECT, zwraca tabelę wynikową. stm.executeUpdate(…); dla zapytań modyfikujących dane w bazie: CREATE TABLE…, DROP TABLE…, INSERT…, UPDATE…, DELETE…. zwraca liczbę zmodyfikowanych rekordów lub wartość -1, np. dla instrukcji CREATE. stm.execute(…); Wykonuje dowolną instrukcję SQL i zwraca wartość typu booolean – true, jeśli powstała tabela wynikowa, false, w przeciwnym przypadku. Wynik, będący tabelą wynikową lub liczbą zmodyfikowanych rekordów, uzyskujemy za pomocą dodatkowego odwołania do obiektu Statement. Ten sam obiekt typu Statement może być wielokrotnie używany do wykonywania różnych instrukcji SQL.
19
Drugi przykład – „DataBaseOperations”
20
Instrukcja SQL SELECT, tabele wynikowe i kursory
W wyniku wykonania instrukcji SELECT powstaje tabela wynikowa. Jest ona w Javie dostępna poprzez obiekt typu ResultSet. ResultSet jest tworzony przez obiekt Statement po wykonaniu metody executeQuery albo execute z poleceniem SELECT. String query = "SELECT * FROM tabela;"; ResultSet rs = stm.executeQuery(query); Zasoby z danymi, do których odwołuje się ResultSet znajdują się po stronie systemu bazodanowego. Obiekt ResultSet reprezentuje tabelę rekordów z danymi. Dane z obiektu ResultSet odczytuje się, podobnie jak z pliku, za pomocą kursora, który przesuwa się nad kolejnymi rekordami w tabeli za pomocą metod next i previous. Kursor inicjalnie jest ustawiony przed pierwszym rekordem tabeli.
21
Obiekt ResultSet Przy tworzeniu obiektu Statement można określić jak będzie się zachowywać obiekt ResultSet: Statement stm = conn.createStatement(rsType, rsCon); przy czym oba argumenty createStatement są typu int, a odpowiadające im stałe są zdefiniowane w klasie ResultSet. Argument rsType [resultSetType] określa możliwości poruszania kursorem. Argument rsCon [resultSetConcurrency] określa możliwość równoczesnego wprowadzania zmian w tabelach.
22
Obiekt ResultSet (2) Argument rsType może przyjmować następujące wartości: ResultSet.TYPE_FORWARD_ONLY kursor można przesuwać tylko do przodu po jednym rekordzie; ResultSet.TYPE_SCROLL_INSENSITIVE kursor można dowolnie przesuwać, dane w tabeli nie są wrażliwe na równoczesne zmiany; ResultSet.TYPE_SCROLL_SENSITIVE kursor można dowolnie przesuwać, dane w tabeli są wrażliwe na równoczesne zmiany. Aby można było przemieszczać kursor w dowolnie wybrane pozycje należy wybrać jeden z typów TYPE_SCROLL_INSENSITIVE lub TYPE_SCROLL_SENSITIVE.
23
Obiekt ResultSet (3) Argument rsCon decyduje o możliwości modyfikowania danych w bazie i może przyjmować następujące wartości: ResultSet.CONCUR_READ_ONLY kursor możne tylko czytać dane z tabeli; ResultSet.CONCUR_UPDATABLE rekord, na który wskazuje kursor można dowolnie zmodyfikować i zmiany te będą zapamiętane w bazie danych. Przykład obiektu Statement, który może utworzyć ResultSet, w którym będzie można dowolnie przemieszczać kursor oraz modyfikować dane: Statement stm = conn.createStatement( ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
24
Obiekt ResultSet (4) Obiekt Statement utworzony za pomocą: Statement stm = conn.createStatement(); może wygenerować obiekt ResultSet typu forward-only. Należy zamykać ResultSet po wykorzystaniu (rs.close()), aby zwolnić zasoby. ResultSet jest zamykany automatycznie, gdy zamykamy obiekt Statement lub gdy ten sam obiekt wykorzystywany jest ponownie do wykonania innej instrukcji SQL (powstaje wtedy nowy ResultSet).
25
Przemieszczanie kursora
Interfejs ResultSet zawiera metody przemieszczające kursor, z których korzystamy przy przeglądaniu tabeli wynikowej. Metody przemieszczające kursor w obiekcie ResultSet: boolean next () boolean previous () boolean first () boolean last () boolean beforeFirst () boolean afterLast () boolean absolute (int n) boolean realtive (int n) Metody przemieszczające kursor w obiekcie ResultSet zwracają wartość boolowską true, gdy kursor ustawi się na jakimś rekordzie w tabeli albo false, gdy kursor wyskoczy poza tabelę. Rekordy w obiekcie ResultSet są numerowane od 1.
26
Przemieszczanie kursora (2)
next() – przesuwa kurs do następnego wiersza. Jeśli wiersz jest ostatnim zwraca fałsz. previous() – przesuwa kurs jedną pozycje do tyłu. Zwraca fałsz jeśli kurs jest ustawiony na pierwszym wierszu. first() – przesuwa kurs na pierwsza pozycję. Zwraca fałsz jeśli ResultSet nie zawiera ani jednego wiersza. last() – przesuwa kurs do ostatniego wiersza w obiekcie ResultSet. Zwraca fałsz jeśli obiekt ResultSet nie zawiera żadnego wiersza. beforeFirst() – ustawia kursor na pozycję początkową przed pierwszym wierczem. afterLast() – przesuwa kurs na pozycję za ostatnim wierszem. relative(int rows) – przesuwa kursor do obecnej pozycji. absolute(int row) – pozycjonuje kursor na określonym wierszu.
27
Pobieranie wartości pól
Do pobierania wartości z poszczególnych kolumn tabeli wynikowej służą metody getTTT(…) interfejsu ResultSet, które dokonują automatycznej konwersji pomiędzy typem pola definiowanym w SQL a typem Javy TTT (TTT oznacza tu jakiś typ np. int lub String). ResultSet rs=stmt.executeQuery(query); while (rs.next()) { TTT pole=rs.getTTT(column); } gdzie column to nazwa (String) lub numer kolumny (int).
28
Obsługa pól z wartością NULL
Odczytując wartość pola numerycznego wskazywanego przez ResultSet metodą getInt możemy otrzymać wartość 0 lub -1 – wtedy nie wiemy, czy jest to wartość zapisana w tym polu czy może efekt przekształcenia null do typu int. Rozwiązaniem tego problemu jest metoda wasNull, która zwraca boolean i mówi nam czy ostatnio przeczytana wartość była null: int wiek = rs.getInt("wiek"); if (rs.wasNull()) {/*…*/} Innym rozwiązaniem jest użycie metody getObject: Integer wiek = (Integer)rs.getObject("wiek"); if (wiek==null) {/*…*/}
29
Modyfikowalna tabela wynikowa
Jeżeli sterownik JDBC dopuszcza modyfikowalny ResultSet – typ ResultSet.CONCUR_UPDATABLE, możemy użyć wobec obiektu typu ResultSet metod updateTTT(…), updateRow(…), insertRow(…) deleteRow(…). Metody te pozwalają na dodawanie, modyfikowanie i usuwanie rekordów bez pośredniego użycia instrukcji SQL, operując na obiekcie RsultSet. Przed wywołaniem tych metod należy ustawić kursor, tak aby wskazywał odpowiedni rekord.
30
Modyfikowanie rekordów
Metody modyfikujące dane w rekordzie pod kursorem w obiekcie ResultSet: void updateXxx (int col, Xxx val) void updateXxx (String col, Xxx val) void updateNull (int col) void updateNull (String col) void updateRow () Metody updateXxx modyfikują pole typu Xxx, na przykład updateInt, updateDouble, updateString. Pola w rekordzie są numerowane od 1. Metoda updateRow zapisuje zmienione wartości i musi być wywołana przed przejściem do następnego rekordu.
31
Wstawianie i usuwanie rekordów
Metody wstawiające nowy rekord do tabeli w obiekcie ResultSet: void moveToInsertRow () void insertRow () boolean rowInserted () Metoda moveToInsertRow przesuwa kursor do miejsca, w którym będzie można zapisać nowy rekord. Po wypełnieniu rekordu danymi za pomocą metod updateXxx wstawiamy nowy rekord do tabeli metodą insertRow. Metody usuwające rekord pod kursorem w obiekcie ResultSet: void deleteRow () Metody deleteRow nie wolno używać w stosunku do nowowstawionego rekordu.
32
Metainformacje o tabeli wynikowej
Metainformacje o tabeli wynikowej uzyskujemy za pomocą metody getMetaData: ResultSetMetaData rsmd = rs.getMetaData(); W obiekcie ResultSetMetaData mamy zbiór metod do wyciągania informacji o tabeli wynikowej: getcolumnCount () getColumnName (int n) getColumnDisplaySize (int n) getColumnType (int n) getColumnTypeName (int n) getColumnClassName (int n) i wiele innych
33
Zapytanie preinterpretowane
W JDBC można tworzyć procedury parametryzowane, w których podaje się wzorzec ze znacznikami (pytajniki) zastępowanymi konkretnymi wartościami przed wywołaniem (obiekty typu PreparedStatement). Obiekt klasy PreparedStatement tworzymy podobnie jak Statement: PreparedStatement stmt = conn.prepareStatement(”…”); W parametrze mogą wystąpić znaki zapytania (numerowane od 1), które uzupełniamy odpowiednimi wartościami za pomocą metod setXxx (gdzie Xxx oznacza typ parametru, na przykład stmt.setString(nr,arg), stmt.setInt(nr,arg), itp); po wypełnieniu znaczników konkretnymi wartościami można wykonać polecenie (używając na przykład metody execute()).
34
Przygotowane wyrażenia
Przygotowane wyrażania reprezentuje obiekt preparedStatement i wykorzystywany jest w przypadku częstego wykonywania tego samego zapytania na bazie danych Zaletą jest to, że wyrażanie zostało wcześniej skompilowane. Jest wymagana komplikacja przed zapytaniem do bazy danych, wysłany jest jedynie SQL. Przykład PreparedStatement updateSales = con.prepareStatement( "UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ?"); ... updateSales.setInt(1, 75); updateSales.executeUpdate():
35
Obsługa transakcji Obsługa transakcji jest w JDBC sterowana obiektem Connection. Przy tworzeniu połączenia włączany jest tryb auto-commit – każda pojedyncze wyrażenie jest wykonywane jako osobna transakcja. Aby samodzielnie sterować transakcjami trzeba właściwość auto-commit ustawić na false: conn.setAutoCommit(false); Po wykonaniu kilku poleceń na bazie możemy je zatwierdzić poleceniem commit albo anulować poleceniem rollback. Istnieje też metoda getAutoCommit, która informuje o trybie auto-commit obiektu Connection.
Podobne prezentacje
© 2024 SlidePlayer.pl Inc.
All rights reserved.