Podpięcie bazy danych w Javie
Skoro znamy już podstawowe operacje na bazach danych SQL to czas wykorzystać je bezpośrednio w naszym projekcie. Przed przystąpieniem do lekcji pamiętaj, aby twój serwer MySQL był włączony – domyślnie sam się włącza wraz z uruchomieniem systemu Windows.
W ostatnich lekcjach poznałeś również czym są branche oraz czym jest ich mergowanie – w takim razie będziemy używać tej wiedzy w tej lekcji. Nic tak nie uczy jak praktyczne zastosowanie, więc do dzieła!
Na początek… Drivery!
O ile w konsoli MySQL mogliśmy pisać zapytania SQL to w Javie nie możemy bezpośrednio tego robić. Będziemy potrzebować do tego oczywiście konkretnych klas, ale również i driverów…
Drivery to nic innego jak sterowniki, które potrafią “rozmawiać” z konkretną bazą danych – jest w końcu ich wiele np. MySQL, postgresql, MariaDB itd.
Podsumowując – o ile zapytania dla każdych z tych baz są tworzone tak samo to różni je tylko driver, które definiują jak wygląda rozmowa między Javą, a konkretną bazą danych!
Drivery dodaje się trochę inaczej niż inne biblioteki – wszystkie inne biblioteki dodawane są przez kompilator w czasie kompilowania projektu – czyli compile scope.
Drivery muszą być wykorzystywane w czasie rzeczywistym działania aplikacji czyli runtime scope – nie biorą one udziału w kompilacji, są wykorzystywane dopiero podczas działania programu.
Dodawać można je na różne sposob, m.in dodając je do projektu w Intellij Idea do tzw. classPath.
My jednak zrobimy to przy użyciu Mavena, który zrobi to wszystko za nas – oczywiście z pomocą kilku mavenowskich pluginów – czyli dodatków. 😉
Ruszajmy – nowy branch!
Na początek sklonuj repozytorium z poprzedniej lekcji:
git clone https://github.com/1024kb-pl/KJOP_UserDao.git
Oczywiście zacznijmy od stworzenia nowego brancha – ja go nazwę user-dao
git checkout -b user-dao
Mając nowy branch możemy przejść do implementacji operacji bazy danych w Javie.
Driver
Tak jak wspomniałem my będziemy wykorzystywać maven do zaciągnięcia mysql-connectora – czyli drivera.
Wystarczy do pliku pom.xml dodać dependency:
<dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> </dependencies>
Dzięki temu Maven zaciągnie ze zdalnego repozytorium mysql-connector-java potrzebny do komunikacji z MySQL.
Ale to jeszcze nie wszystko – już tłumaczę.
Każdy projekt, który składa się z większej ilości plików (plików skompilowanych .class) jest spakowany do jednego archiwum o rozszerzeniu .jar. Właśnie tam podczas kompilacji Maven musi automatycznie dorzucić nam odpowiedni driver.
Zrobimy to tym zapisem, już wszystko tłumaczę.
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>2.4</version> <configuration> <archive> <manifest> <mainClass>Main</mainClass> <addClasspath>true</addClasspath> </manifest> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
Znacznik build oznacza, że będzie plugin uruchamiany podczas procesu budowania projektu. Plugin, który zostanie uruchomiony to maven-assembly-plugin w wersji 2.4, w którym konfigurujemy m.in manifest.
Czym jest manifest? Manifest to nic innego jak plik tekstowy, w którym zawierają się podstawowe informacje o jarze – a co najważniejsze punkt uruchomieniowy projektu czyli klasa Main.
Przykładowy plik manifest:
Manifest-Version: 1.0 Archiver-Version: Plexus Archiver Built-By: Klimek Created-By: Apache Maven 3.5.4 Build-Jdk: 1.8.0_181 Main-Class: Main
Dzięki temu JRE wie, którą klasę ma uruchomić z Jara.
Dodatkowo plugin pakuje nam wszystkie potrzebny .classy do jara:
<execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution>
Mając tak zbudowany plik pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>KJOP</groupId> <artifactId>dao</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>2.4</version> <configuration> <archive> <manifest> <mainClass>Main</mainClass> <addClasspath>true</addClasspath> </manifest> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
Niczego nie musimy już się bać i możemy łączyć się z bazą danych. 😉
Dao
Na poczatku stwórzmy sobie klasę UserDao z kilkoma polami:
public class UserDao { private Connection connection; private final String databaseName = "people"; private final String tableName = "employees"; private final String user = "root"; private final String password = "admin"; }
Pole Connection będzie odpowiedzialne za połączneie z bazą – reszta pól to pola konfiguracyjne, czyli wymagane do połaczenia z bazą danych. Wejdź do konsoli MySQL tak jak w poprzednich lekcjach i sprawdź nazwę bazy i tabeli umieszczonej w niej, którą stworzyliśmy w poprzednich lekcjach – ja własnie wykorzystuję dokładnie tą tabelę, która wspólnie utworzyliśmy.
W konstruktorze będziemy musieli nawiązać połączenie – ja wyrzuciłem to do osobnej metody init, aby konstruktor wyglądał ładniej.
public UserDao() { init(); } private void init() { try { Class.forName("com.mysql.jdbc.Driver"); connection = DriverManager.getConnection("jdbc:mysql://localhost/"+databaseName+"?useSSL=false", user, password); } catch(Exception e) { e.printStackTrace(); } }
Już tłumaczę co tu się dzieje – w linii:
Class.forName("com.mysql.jdbc.Driver");
Wybieramy sterownik do naszej bazy danych czyli mysql.
W kolejnej linii:
connection = DriverManager.getConnection("jdbc:mysql://localhost/"+databaseName+"?useSSL=false", user, password);
Nawiązujemy już połączenie z bazą daynch – jbdc:mysql jest zrozumiały przez driver, localhost jest zaś adresem lokalnej bazy danych, podajemy również tam nazwę bazy danych oraz użytkownika i hasło – w moim przypadku jest to root i admin – dokładnie tak jak podawałem podczas instalacji MySQL.
Mając już zainicjowane połączenie możemy wykonać pierwsze polecenie na bazie danych, a czemu nie!
Select
Na początek wykonajmy selecta – wyciągniemy wszystkich userów z bazy danych.
public List<User> getAllUsers() { List<User> users = new LinkedList<User>(); return users; }
I została tylko część bazo danowa. 😉
Na początku musimy stworzyć komunikat do bazy danych:
Statement statement = null; try { statement = connection.createStatement(); } catch (SQLException e) { e.printStackTrace(); }
Stworzyć zapytanie – tak samo jak w SQL, my chcemy wyciągnąć wszystkich z tabeli o nazwie employees.
String query = "select * from " + tableName;
Wynik możemy przypisać do ResultSet – czyli zbioru rezultatów zwróconych przez SQL.
ResultSet resultSet = statement.executeQuery(query);
A następnie po nim całym przejść i stworzyć na podstawie danych nowych userów.
while (resultSet.next()) { String name = resultSet.getString("name"); String lastname = resultSet.getString("lastname"); Integer age = resultSet.getInt("age"); User user = new User(name, lastname, age); users.add(user); }
UWAGA! Nazwy podawane jako argument funckji getString, getInt są nazwami kolumn, a nie nazwami pól w klasie User!
Po tym wszystkim zamykamy komunikat:
statement.close();
A cała metoda wygląda teraz tak:
public List<User> getAllUsers() { List<User> users = new LinkedList<User>(); Statement statement = null; try { statement = connection.createStatement(); String query = "select * from " + tableName; ResultSet resultSet = statement.executeQuery(query); while (resultSet.next()) { String name = resultSet.getString("name"); String lastname = resultSet.getString("lastname"); Integer age = resultSet.getInt("age"); User user = new User(name, lastname, age); users.add(user); } statement.close(); } catch (SQLException e) { e.printStackTrace(); } return users; }
Sprawdźmy jej działanie w klasie Main:
UserDao userDao = new UserDao(); System.out.println(userDao.getAllUsers());
Czas na kompilację całego projektu – możemy uruchomić klasę Main lub zbudować całego jara komendą Maven:
mvn package
I zbuduje nam się cały jar z sufiksem jar-with-dependencies, który można uruchomić bez problemu już na każdym JRE, tak samo można w Intellij Idea można kliknąć prawym i wybrać: Run.
Jeśli miałeś oczywiście jakieś rekordy w tabeli to powinno coś Ci się wyświetlić w konsoli – ja otrzymałem taki rezultat:
[User{name='Johny', lastname='Rambo', age=34}, User{name='Jan', lastname='Kowalski', age=45}, User{name='young', lastname='Kowalska', age=19}, User{name='young', lastname='Bravo', age=33}, User{name='young', lastname='Red', age=12}, User{name='kamil', lastname='klimek', age=33}, User{name='kamil', lastname='klimeeek', age=33}]
Jak widać coś się udało zaciągnąć z bazy danych – na udowodnienie wycinek z konsoli MySQL.
select * from employees; +----+-------+----------+-----+ | ID | name | lastname | age | +----+-------+----------+-----+ | 5 | Johny | Rambo | 34 | | 6 | Jan | Kowalski | 45 | | 7 | young | Kowalska | 19 | | 9 | young | Bravo | 33 | | 10 | young | Red | 12 | | 11 | kamil | klimek | 33 | | 13 | kamil | klimeeek | 33 | +----+-------+----------+-----+ 7 rows in set (0.00 sec)
Wszystko się zgadza – idźmy dalej. 😉
Insert
Warto też by było dodawać jakiś userów do bazy danych – zrobimy to analogicznie co select, tylko z jedną małą różnicą, czyli wstrzykiwaniem wartości w Query. 😉
Tworzymy metodę createUser, tak samo jak metodę getAllUser:
public void createUser(User user) { PreparedStatement statement; try { String query = "insert into " + tableName + " (name, lastname, age) values(?, ?, ?)"; statement = connection.prepareStatement(query); statement.close(); } catch (SQLException e) { e.printStackTrace(); } }
Spójrz, że korzystamy teraz z prepareStatement oraz znaków zapytania – dzięki takiemu zabiegowi w łatwy sposób możemy wstrzyknąć wartości w miejsca znaków zapytania w query.
O właśnie w ten sposób:
statement.setString(1, user.getName()); statement.setString(2, user.getLastname()); statement.setInt(3, user.getAge());
UWAGA! Parametry są liczone od 1, a nie od zera jak tablice!
I jeszcze wykonajmy nasze polecenie:
statement.execute();
I cała metoda wygląda tak:
public void createUser(User user) { PreparedStatement statement; try { String query = "insert into " + tableName + " (name, lastname, age) values(?, ?, ?)"; statement = connection.prepareStatement(query); statement.setString(1, user.getName()); statement.setString(2, user.getLastname()); statement.setInt(3, user.getAge()); statement.execute(); statement.close(); } catch (SQLException e) { e.printStackTrace(); } }
Jeszcze przetestujmy działanie tej metody w Main – zmieniłem lekko metodę createUser na:
static Scanner scanner = new Scanner(System.in); static UserDao userDao = new UserDao(); public static void createUser() { String name, lastname; Integer age; System.out.println("Type a name: "); name = scanner.next(); System.out.println("Type a lastname: "); lastname = scanner.next(); System.out.println("Type your age: "); age = scanner.nextInt(); User user = new User(name, lastname, age); userDao.createUser(user); System.out.println("Utworzono Usera: " + user.toString()); }
I wywołałem ją oczywiście. 😉
public static void main(String[] args) { createUser(); calculate(); UserDao userDao = new UserDao(); System.out.println(userDao.getAllUsers()); }
I powinno działać poprawnie. 😉
A na koniec pracy..
Nie można zapomnieć oczywiście w ciągu pracy o commitach, a po wykonaniu zadania o merge!
Dlatego robimy
git checkout master
A następnie dołączamy gałąź do głównej gałęzi:
git merge user-dao
Oraz możemy wypchnąć zmiany na zewnętrzny serwer.
git push origin --all
Podsumowanie
I to tyle na temat podłączania bazy danych do Javy, nie było to zbyt skomplikowane, o ile zna się choć trochę składnie SQL. Nie ma jednak co spoczywać na laurach i należy wykonać przygotowane zadania, aby mieć pewność, że wszystko się rozumie!
- Napisz metodę deleteUser, która będzie usuwały po lastName.
- Napisz metodę updateUser, która będzie otrzymywała obiekt User i na podstawie przechowywanego w niej ID będzie aktualizować obiekt w bazie danych.
- Obie metody przetestuj w klasie Main.
Kod z tej lekcji oraz przykładowe rozwiązania zadań możesz znaleźć tutaj. 😉