Za nami kolejny bardzo konkretny i bardzo obfity w wiedzę i praktykę blok kursowy. Było o MySQL, MongoDB, wreszcie po tygodniu klepania selectów, insertów, joinów i update’ów odpaliliśmy ponownie IntelliJ i nasze bazy danych zaciągaliśmy do aplikacji w Javie. Oto krótki poradnik jak w kwadrans postawić funkcjonujące połączenie między bazą danych a Twoją apką z użyciem JDBC.

Z tego artykułu dowiesz się:

  • Czym jest JDBC?
  • Jak ustanowić połączenie aplikacji w Javie z bazą danych z użyciem JDBC?
  • Jakie klasy JDBC odpowiadają za wysyłanie zapytań i odbieranie danych z bazy?
  • Co to jest DOA i dlaczego to bardzo ważne pojęcie?

Krok 1 – Fundamenty. Bez teorii w tym temacie ani rusz. Czym jest JDBC? To skrót od Java Database Connectivity – domyślnego dla Javy API wykonywania operacji łączenia z bazą danych i manipulowania danymi w tejże bazie. JDBC jest więc biblioteką, która dostarcza nam prostych i szybkich metod za pomocą których najpierw ustawiamy połączenie z bazą danych, a następnie wykonujemy na niej operacje. To do dzieła.

Krok 2 – Zaczynamy od dodania dependencji do Maven’a. Najświeższe wersje do ściągnięcia tutaj.

Krok 3 – Utworzenie klasy DatabaseServer. Moglibyśmy obyć się bez niej, ale – uwierzcie mi – gdy wrzucicie to wszystko od razu do metody statycznej main to błyskawicznie stracicie klarowność. Klasa ta zawiera wszystkie dane i operacje związane z utworzeniem połączenia z bazą danych. Do klasy DatabaseServer dodajemy:

  • pola z modyfikatorem dostępu private, które definiują dane dostępowe – databaseName, databaseAddress, userName, userPassword;
  • pole z obiektem klasy Connection. Connection to interfejs biblioteki SQL, który nawiązuje połączenie z Bazą danych (surprise, surprise 😉
  • metodę connect:

    W metodzie tej przekazujemy pola, które zdefiniowaliśmy wcześniej.

Krok 4 – Na tym etapie mamy:
– ustawione połączenie z bazą danych (za pomocą interfejsu connection)
– przekazane z pomocą klasy DriverManager dane bazy danych
Teraz potrzebujemy czegoś, co przekaże zapytanie SQL’owe do bazy danych – do tego używany jest interfejs statement.

Zwróćcie uwagę na umyślne rzucenie wyjątku IllegalStateException – nie możemy przecież operować na bazie danych… nie będąc połączonymi z bazą danych.

Krok 5 – Potrzebujemy też w klasie DatabaseServer metody kończącej połączenie – jest ona niezbędna do zamknięcia połączenia i zwolnienia zasobów.

To na tyle, jeżeli chodzi o obsługę połączenie z bazą danych. Przejdźmy teraz do samego rdzenia, czyli wysłania zapytania i odbierania danych z bazy.

Krok 6 – W głównej klasie z metodą statyczną main tworzymy instancję klasy DatabaseServer do której przekazujemy dane dostępowe do bazy danych. W przypadku mojej, testowej bazy danych wszystko siedzi na localhost – czyli na moim komputerze. Na potrzeby tego artykułu stworzyłem prostą bazę danych o nazwie bookstore. Hasło i sposób jego przekazywania to rzecz jasna totalna antypraktyka – proszę Cię więc, na potrzeby jakichkolwiek testowych aplikacji i połączeń – nie przekazuj w ten sposób haseł, którymi posługujesz się na co dzień!

Krok 7 – Następnie do Stringa przekazujemy zapytanie do bazy danych, wstawiamy metodę connect oraz z pomocą interfejsu resultset przekazujemy zapytanie. ResultSet to interfejs, który jest czymś w rodzaju gettera – kursora, który przechodzi przez wskazane wiersze w tabeli i wyciąga z nich określone typami dane. Sposób działania ResultSeta łatwo prześledzić na podstawie przykładu:

W metodzie resultSet.next(), która zwraca booleana odwzorowujemy strukturę naszej tabeli – w finalnych nawiasach każdego wiersza włożony jest String, który musi być dokładnie taki sam jak nazwa kolumny!!! To bardzo ważne. Jeżeli pomylimy nazwę kolumny, wprowadzimy literówkę dostaniemy wyjątek:
java.sql.SQLException: Column ‚autho2r’ not found.

Dobrze jest zawczasu pomyśleć o tym do jakiego typu kolekcji danych przekażemy dane z bazy danych. Na potrzeby tego prostego przykładu listę wszystkich książek z tabeli books „wrzucam” natychmiastowo do ArrayListy Stringów. Drukuję je w konsoli za pomocą pętli:

Doszliśmy więc do pułapu na którym mamy rekordy z bazy danych w naszej aplikacji w Javie. Podsumowując całość procesu:

  1. do obsługi baz danych w Javie korzystamy z JDBC – domyślnego API Javy do ustanawiania połączeń i obsługi baz danych. Klasy JDBC znajdują się w pakiecie java.sql – należy pamiętać o uprzednim dodaniu pakietu do dependencji w Mavenie.
  2. ustanawianie połączenia z bazą danych odbywa się przez interfejs Connection i klasę DriveManager
  3. Do przekazywania instrukcji operujących na bazie danych używamy interfejsu Statement z dwoma głównymi metodami – createStatement i executeStatement
  4. Rezultat zapytania SQL’owego, którego intencją jest pobranie określonych rekordów do aplikacji, jest przekazywany przez interfejs ResultSet, który działa jak getter zwracający określony typ danych.

Powyższy przykład to oczywiście bardzo prosta sytuacja – nie robimy bowiem nic innego, jak tylko zaciągamy dane z bazy danych. Manipulacja danymi – dodawanie, aktualizowanie, usuwanie – to wbrew pozorom nic skomplikowanego. Podstawowe metody dostępne w interfejsie Statement to:

  1. – executeUpdate() – służy do aktualizowania (update), dodawania (insert into) i usuwania (delete) rekordów w bazie danych
  2. – addBatch() i executeBatch() służy do zmian jednocześnie na wielu rekordach – najpierw za pomocą addBatch() wprowadzamy kolejno instrukcje SQL’owe, później executeBatch() je wykonujemy.

To co jest trudniejsze to odzwierciedlenie struktury bazy danych w obiektowej naturze Javy. W powyższej bazie – bookstore – należałoby bowiem stworzyć oddzielne klasy dla każdej z tabel. Następnie, dla każdej klasy – oddzielne interfejsy, które realizowałby podstawowy zakres zapytań SQL’owych (get, update, add, delete). W tym momencie z pomocą przychodzi jedna z głównych koncepcji programowania obiektowego – DAO, czyli Data Access Object. U źródła DAO jest wzorcem projektowym, w którym definiujemy sposób w jaki Java ma uzyskiwać dostęp do danych i nimi manipulować. W praktyce DAO realizuje jeden z filarów paradygmatu obiektowego jakim jest hermetyzacja (enkapsulacja). Dzięki DAO separujemy od siebie elementy aplikacji, które mogą, ale nie powinny nic o sobie wiedzieć – bazę danych (element zewnętrzny) i naszą aplikację. DAO jest naszym pośrednikiem – łączy się z bazą danych, pobiera dane i przekazuje je do aplikacji. Podobnie działa to w drugą stronę. Dzięki temu dane, na których pracuje aplikacja są oddzielone od tych w bazie danych.

Jak zastosować DAO w praktyce? Zerknijcie na mojego gita –repozotyrium Databases, pakiet bookstoreDB.

Kilka źródeł, które przydadzą się w nauce podstaw Baz Danych i JDBC:
Bardzo skrótowy, ale merytoryczny i fajnie przekazany tutorial z JDBC na JavaStart.pl
Czteroodcinkowy tutorial MySQL z kanału Pasja Informatyki
Dokumentacja Oracle’a – jak zawsze niezbędna