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!

  1. Napisz metodę deleteUser, która będzie usuwały po lastName.
  2. 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.
  3. Obie metody przetestuj w klasie Main.

Kod z tej lekcji oraz przykładowe rozwiązania zadań możesz znaleźć tutaj. 😉

 

 

 

 

 

Kamil Klimek

Od 2016 jestem programistą Java. Przez pierwsze 4 lata pracowałem jako Full Stack Java Developer. Później postanowiłem postawić nacisk na Javę, żeby jeszcze lepiej ją poznać.

Subscribe
Powiadom o
guest
0 komentarzy
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x