430 likes | 570 Views
Programowanie sieciowe w Javie. Michał Kuciapski m.kuciapski@univ.gda.pl. Bazy danych. Bazy danych. Metody dostępu. JDBC.
E N D
Programowanie sieciowe w Javie Michał Kuciapski m.kuciapski@univ.gda.pl
Bazy danych Metody dostępu
JDBC • JDBC (Java Database Connectivity) jest interfejsem(sterownikiem) niskiego poziomu języka Java przeznaczony do bezpośredniego wykonywania poleceń SQL (Structured QueryLanguage). • JDBC jest odpowiedzialny za: • tworzenie połączenia z bazą danych • wysłanie polecenia (poleceń) SQL • przetwarzanie otrzymanych wyników
ODBC • ODBC (Open DataBase Connectivity) jest interfejsem Microsoftu umożliwiającym również korzystanie z baz danych, co wiąże się jednak z szeregiem nieodgodności: specyficzność i ograniczenie metod programowania, konieczność ręcznego konfigurowania parametrów połączenia na każdej platformie. • Dla ułatwienia programowania dostępu do baz z połączeniami ODBC utworzony został most JDBC-ODBC automatycznie …
DBMS • DBMS (DataBase Management System) jest systemem zarządzania bazami danych, którego rolą jest: tworzenie struktury bazy, wypełnianie bazy danych, usuwanie, aktualizacja rekordów, nadawanie praw dostępu, itp. • DBMS najczęściej instalowany jest najczęściej wraz z instalacją sterowników.
Bazy danych Połączenia
Sterowniki • Sterowniki, są pakietami zawierającymi implementację deklarowanych klas, atrybutów i metod związanych z obsługą dostępu i zarządzania bazą danych odnośnie: • inicjowania i zamykania połączeń • wykonywania zapytań (interfejs Statement) • zwracania i przetwarzania wyników zapytań (interfejs ResultSet) • Sterowniki muszą występować po stronie dokonującej połączenie z bazą danych a w przypadku appletów sterownik musi być zainstalowany na serwerze WWW tam, skąd pochodzi applet.
Sterowniki • Dla połączenia z bazą danych konieczne jest zainstalowanie odpowiedniego dla niej sterownika. Dokonuje się tego poprzez: • program instalacyjny • rejestracje klasy lub pakietu • Klasę lub pakiet sterownika rejestrujemy poprzez umieszczenie go w odpowiednim podkatalogu jdk oraz podanie nazwy jako parametru metody statycznej Class.forName() – np. dla MySQLa Class.forName("com.mysql.jdbc.Driver")
Koncepcja • Utworzenie połączenia z bazą danych polega utworzeniu odpowiedniego obiektu klasy Connection. W tym celu stosuje się jedną z przeciążonych statycznych metod getConnection klasy DriverManager. • Każda metoda getConnection zawiera jako argument adres URL dostępu do bazy - jdbc:sterownik:lokalizacja
Koncepcja c.d. • jdbc:sterownik:lokalizacja, gdzie: • jdbc – element stały określa nazwę protokołu • sterownik – określa nazwę sterownika lub mechanizmu połączenia, np.: odbc, mysql • lokalizacja – opis lokalizacji bazy danych w postaci //host:port/ścieżka • Przykłady: • jdbc:odbc:baza_testowa • jdbc:mysql://bsvc.univ.gda.pl:4000/baza_testowa
Tworzenie połączenia • Połączenie dokonywane jest za pomocą metody statycznej getConnection() klasy DriverManager: • Connection getConnection(String url) • Connection getConnection(String url, String info) • Connection getConnection(String url, String użytkownik, String hasło) • Aby móc skorzystać ze statycznej metody getConnection() należy zaimportować klasy pakietu java.sql.*. Ponadto wymaga ona obsłużenia błędu SQLException.
Przykład • import java.sql.*; • public class BazaPoloczenie { • public static void main(String args[]){ • try{ • Class.forName("com.mysql.jdbc.Driver"); • System.out.println("Połączenie za pomocą wyłącznie url"); • Connection poloczenie1 = DriverManager.getConnection("jdbc:mysql://localhost/firmatest?user=root&password=p@ssw0rd"); • System.out.println("Połączenie za pomocą: url, loginu i hasła"); • Connection poloczenie2 = DriverManager.getConnection("jdbc:mysql://localhost/firmatest","root","p@ssw0rd");
Przykład c.d. • } • catch(ClassNotFoundException e) • { • System.out.println("Brak klasy: " + e.getMessage()); • } • catch(SQLException e) • { • System.out.println("Błąd połączenia: " + e.getMessage()); • } • } • }
Bazy danych Tworzenie obiektów poleceń
Wykorzystywane interfejsy • W celu wysłania polecenia SQL należy stworzyć jeden z typów obiektów: • Statementstanowi kontener dla wykonywanych poleceń SQL i umożliwia wysyłanie poleceń SQL nie zawierających parametrów • PreparedStatement używany jest do wykonywania przygotowanych poleceń SQL, zawierających jedno lub więcej pól parametrów, oznaczanych znakiem "?" • CallableStatement jest wykorzystywany do tworzenia odwołań do przechowywanych w bazie danych procedur
Tworzenie interfejsów • W celu utworzenia obiektu dla wykonywania poleceń należy wywołać w zależności od typu tworzonego obiektu jedną z metod statycznych dla obiektu klasy Connection: • createStatement() – dla utworzenia obiektu klasy • Statement • prepareStatement()- dla utworzenia obiektu klasy • PreparedStatement • prepareCall() - dla utworzenia obiektu klasy • CallableStatement
Definiowanie typów wywoływania poleceń • Metoda createStatement posiada 3 przeciążenia: • Statement createStatement()– tworzy obiekt klasy Statement dla przesyłania zapytań SQL do bazy • Statement createStatement(int resultSetType, int resultSetConcurrency) – tworzy obiekt klasy Statement, dla którego generowane wyniki zapytań będą mieć odpowiedni format oraz modyfikowalność • Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) – tworzy obiekt klasy Statement, dla którego generowane wyniki zapytań będą mieć odpowiedni format, modyfikowalność oraz zachowania kursora
Wartości parametrów tworzenia obiektów poleceń • Dla resultSetType: • ResultSet.TYPE_FORWARD_ONLY - kursor może poruszać się wyłącznie do przodu • ResultSet.TYPE_SCROLL_INSENSITIVE - kursor może się swobodnie poruszać i nie jest wrażliwy na zmiany dokonywane przez inne kursory • ResultSet.TYPE_SCROLL_SENSITIVE - kursor może się swobodnie poruszać i jest wrażliwy na zmiany dokonywane przez inne kursory
Wartości parametrów tworzenia obiektów poleceń c.d. • DlaresultSetConcurrency • ResultSet.CONCUR_READ_ONLY – zwrócone wartości pól rekordów mogą być wyłącznie odczytywane • ResultSet.CONCUR_UPDATABLE -zwrócone wartości pól rekordów mogą być zmieniane i aktualizowane dla bazy • Dla resultSetHoldability: • ResultSet.HOLD_CURSORS_OVER_COMMIT – obiekt klasy ResultSet reprezentujący zwrócone dane w wyniku zapytania po wykonaniu metody Connection.commit nie ma zostać zamknięty • ResultSet.CLOSE_CURSORS_AT_COMMIT - – obiekt klasy ResultSet reprezentujący zwrócone dane w wyniku zapytania po wykonaniu metody Connection.commit ma zostać zamknięty
Przykład • import java.sql.*; • public class BazaPoloczenie { • public static void main(String args[]){ • try{ • Class.forName("com.mysql.jdbc.Driver"); • System.out.println("Połączenie za pomocą wyłącznie url"); • Connection poloczenie1 = DriverManager.getConnection("jdbc:mysql://localhost/firmatest?user=root&password=p@ssw0rd"); • System.out.println("Tworzenie obiektu połączenia"); • Statement polecenie = poloczenie.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
Metody wykonywania poleceń • Do podstawowych metod wykonywania poleceń należą: • executeQuery() – umożliwia wywoływanie poleceń typu select i zwraca wynik zapytania jako obiekt ResultSet • executeUpdate() - umożliwia wywoływanie poleceń typu: insert , update , create , drop , alter i zwraca liczbę zmienionych wierszy • execute() - przygotowana do obsługi poleceń zwracających większą ilość zbiorów danych (obiektów klasy ResultSet) • W przypadku obiektu PreparedStatement wyrażenie SQL musi być odpowiednio przygotowane – obiekt zawiera prekompilowane wyrażenie SQL. Wymaga to podania wartości parametrów za pomocą metod set.
Przykład • polecenie.executeUpdate("insert into miasto(miasto,gmina,powiat,wojewodztwo) values('Tczew','Tczew','Tczewski','Pomorskie')"); • PreparedStatement poleceniePS = poloczenie.prepareStatement( • "insert into miasto(miasto,wojewodztwo) values(?,?)"); • poleceniePS.setString(1,"Poznań"); • poleceniePS.setString(2,"Wielkopolskie"); • poleceniePS.executeUpdate();
Bazy danych Rezultaty i ich przetwarzanie
Koncepcja • W wyniku zapytania typu executeQuery() jako wynik zwracany jest obiekt klasy ResultSet zawierający będące wynikiem zapytania rekordy. • Możliwe jest wykonywanie szeregu operacji na obiekcie tej klasy: • Przechodzenie kursorem pomiędzy rekordami i pobieranie wartości dla poszczególnych pól rekordu • Dodawanie, usuwanie, aktualizowanie rekordów zarówno dla ResultSet jak i bazy danych – wyłącznie jeśli polecenie dla, którego został utworzony ResultSet było ustawione jako typ ResultSet.CONCUR_UPDATABLE
Metody nawigacji pomiędzy rekordami • Metody służące przechodzeniu pomiędzy rekordami w ramach zwróconego jako wynik zapytania obiektu klasy ResultSet: • previous() – powoduje przejście do rekordu • poprzedniego • next() – powoduje przejście do rekordu następnego • first() – powoduje przejście do rekordu pierwszego • last() – powoduje przejście do rekordu ostatniego • absolute(int rekord) – powoduje przejście do • wskazanego rekordu podanego jako parametr metody
Metody nawigacji pomiędzy rekordami c.d. • W trakcie przechodzenia pomiędzy rekordami metodami previous() i next() konieczne jest sprawdzenie odpowiednio warunków: • isFirst() – zwraca czy bieżący rekord jest pierwszym rekordem w ResultSet • isLast() - zwraca czy bieżący rekord jest ostatnim rekordem w ResultSet
Metody informacyjne dla rekordów i ResultSet • Najważniejsze metody służące pobieraniu informacji o rekordach i obiekcie klasy ResultSet: • getRow()– zwraca indeks bieżącego rekordu • refreshRow()– powoduje odświeżenie wartości wiersza zgodnie z aktualną wartością w bazie danych • getMetaData()– zwraca metadane o definicji rekordu • getType()– pobiera informacje o typie ResultSet • getStatement() – pobiera tekst polecenia, które spowodowało utworzenie obiektu ResultSet • findColumn(String nazwa)– umożliwia sprawdzenie występowania określonej kolumny
Pobieranie danych z ResultSet • Dane z obiektu klasy ResultSet pobieramy za pomocą metody get z przyrostkiem typu danych podając jako parametr bądź indeks kolumny lub jej nazwę: • String getString(int indeksKolumny) • Float getFloat(String nazwaKolumny) • Przykłady: • jtxbImie.setText(rezultat. getString(2)) ; • jtxbPensja.setText(rezultat.getFloat("pensja").toString() );
Przykład • Class.forName("com.mysql.jdbc.Driver"); • poloczenie = DriverManager.getConnection("jdbc:mysql://localhost/firmatest?user=root&password=p@ssw0rd"); • zapytanie = poloczenie.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, • ResultSet.CONCUR_UPDATABLE); • rezultat = zapytanie.executeQuery("select * from towar;"); • rezultat.next(); • wyswietlDane();
Przykład c.d. • try • { • jtfSymbol.setText(rezultat.getString("symbol_towaru")); • jtfNazwa.setText(rezultat.getString("nazwa_towaru")); • jtfOpis.setText(rezultat.getString("opis_towaru")); • jtfCena.setText(rezultat.getString("cena_towaru")); • } • catch(SQLException e) • { • JFrame ramka = new JFrame(); • JOptionPane.showMessageDialog(ramka, "Błąd wyświetlenia • danych: " + e.getMessage(), "Błąd polecenia!", • JOptionPane.ERROR_MESSAGE); • }
Dodawanie rekordów • Dodania rekordu możemy dokonać wyłącznie, jeśli parametr resultSetConcurency jest ustawiony na ResultSet.CONCUR_UPDATABLE. • Procedura dodania rekordu: • Przejście do specjalnego rekordu „wstawiania” za pomocą metody moveToInsertRow() • Ustawienie wartości poszczególnych pól z pomocą metody update z przyrostkiem wskazującym typ wprowadzanych danych i parametrami indeks lub nazwa pola oraz wartość • updateString(StringnazwaKolumny, Stringwartość) • updateFloat(int indeks, Floatwartość)
Dodawanie rekordów c.d. • Procedura dodania rekordu c. d.: • dodanie rekordu do ResultSet oraz bazy danych za pomocą metody insertRow() • Przejście do bieżącego rekordu (czyt. rekordu w którym byliśmy przed przejściem do rekordu wstawiania) za pomocą metody moveToCurrentRow()
Dodawanie rekordów - przykład • rezultat.moveToInsertRow(); • rezultat.updateString("symbol_towaru",jtfSymbol.getText()); • rezultat.updateString("nazwa_towaru",jtfNazwa.getText()); • rezultat.updateString("opis_towaru",jtfOpis.getText()); • rezultat.updateFloat("cena_towaru", Float.parseFloat(jtfCena.getText())); • rezultat.insertRow(); • rezultat.moveToCurrentRow(); • nowyRekord = false;
Usuwanie rekordów • Usunięcia rekordu możemy dokonać wyłącznie, jeśli parametr resultSetConcurency jest ustawiony na ResultSet.CONCUR_UPDATABLE. • Procedura usunięcia rekordu: • Wywołanie metody deleteRow() usuwającej rekord • Przejście do rekordu poprzedniego
Usuwanie rekordów - przykład • try • { • rezultat.deleteRow(); • rezultat.previous(); • wyswietlDane(); • } • catch(Exception e) • { • JFrame ramka = new JFrame(); • JOptionPane.showMessageDialog(ramka, "Błąd dla przycisku • \"Usuń\": " + e.getMessage(), "Błąd polecenia!", • JOptionPane.ERROR_MESSAGE); • }
Aktualizowanie rekordów • Aktualizacja rekordu jest możliwa wyłącznie, jeśli parametr resultSetConcurency jest ustawiony na ResultSet.CONCUR_UPDATABLE. • Procedura aktualizacji rekordu: • Ustawienie wartości poszczególnych pól z pomocą metody update z przyrostkiem wskazującym typ wprowadzanych danych i parametrami indeks lub nazwa pola oraz wartość • updateString(StringnazwaKolumny, Stringwartość) • updateFloat(int indeks, Floatwartość) • Wywołanie metody updateRow()
Aktualizowanie rekordów - przykład • if(rezultat.getString("symbol_towaru") != jtfSymbol.getText()) rezultat.updateString("symbol_towaru",jtfSymbol.getText()); • if(rezultat.getString("nazwa_towaru") != jtfNazwa.getText()) • rezultat.updateString("nazwa_towaru", jtfNazwa.getText()); • if(rezultat.getString("nazwa_towaru") != jtfNazwa.getText()) • rezultat.updateString("opis_towaru", jtfOpis.getText()); • if(rezultat.getString("cena_towaru") != jtfCena.getText()) rezultat.updateFloat("cena_towaru", Float.parseFloat(jtfCena.getText())); • rezultat.updateRow();
Bazy danych Transakcje
Koncepcja • Transakcja składa się z jednego lub więcej poleceń, które zostały wywołane, wykonane i potwierdzone (Commit) lub odrzucone (RollBack). • Transakcja stanowi więc jednostkową operację. Zarządzanie transakcją jest szczególnie ważne gdy chcemy wykonać naraz kilka operacji traktując je od strony logicznej jako jedną.
Procedura • ustawienie pracy w stanie bez potwierdzania za pomocą • połączenie.setAutoCommit(false), gdzie wartość domyślna ustawiona jest na automatyczne potwierdzanie, • wykonanie wyrażeń SQL • potwierdzenie wykonania operacji za pomocą połączenie.commit() , które powoduje, że zmiany spowodowane wyrażeniem SQL stają się stałe. • w przypadku błędu można wysłać polecenie przerwania połączenie.rollback() powodujące odtworzenie stanu przed wykonaniem wyrażenia.
Przykład • Connection poloczenie1 = DriverManager.getConnection("jdbc:mysql://localhost/firmatest?user=root&password=p@ssw0rd"); • System.out.println("Tworzenie obiektu połączenia"); • Statement polecenie = poloczenie.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE); • poloczenie.setAutoCommit(false);
Przykład c.d. • polecenie.executeUpdate("insert into miasto values('Tczew','Tczew','Tczewski','Pomorskie')"); • PreparedStatement poleceniePS = poloczenie.prepareStatement( • "insert into miasto values(?,?,?,?)"); poleceniePS.setString(2,"Poznań"); • poleceniePS.setString(5,"Wielkopolskie"); • poleceniePS.executeUpdate(); • poloczenie.commit(); • catch(SQLException e) • { • poloczenie.rollback(); • }