JavaRush /Blog Java /Random-PL /Twoja pierwsza aplikacja Hibernate

Twoja pierwsza aplikacja Hibernate

Opublikowano w grupie Random-PL
W tym artykule zapoznasz się z jednym z najpopularniejszych frameworków korporacyjnych dla języka Java i stworzysz swoją pierwszą aplikację przy użyciu Hibernate. Nigdy nie słyszałeś o Hibernacji? Może słyszałeś o tym, ale jeszcze nie stosowałeś? A może próbowałeś zacząć, ale nie udało Ci się? We wszystkich trzech przypadkach zapraszamy na cięcie :) Twoja pierwsza aplikacja Hibernate — 1Witam wszystkich! W tym artykule opowiem o głównych cechach frameworka Hibernate i pomogę Ci napisać pierwszą miniaplikację. Do tego potrzebujemy:
  1. Intellij Idea Ultimate Edition;
    Pobierz z oficjalnej strony i aktywuj 30-dniową wersję próbną.
  2. PostgeSQL to jeden z najpopularniejszych nowoczesnych systemów zarządzania bazami danych (DBMS);
  3. Maven (już wbudowany w IDEA);
  4. Trochę cierpliwości.
Artykuł skierowany jest przede wszystkim do osób, które nigdy nie miały styczności z tą technologią, dlatego ilość kodu została maksymalnie ograniczona. Zacznijmy!

Co to jest hibernacja?

Jest to jedna z najpopularniejszych implementacji modelu ORM. Model obiektowo-relacyjny opisuje relacje pomiędzy obiektami oprogramowania a rekordami w bazie danych. Oczywiście funkcjonalność Hibernate jest bardzo szeroka, jednak my skupimy się na najprostszych funkcjach. Nasz cel: stworzyć aplikację CRUD (Create, Read, Update, Delete), która będzie mogła:
  1. Twórz użytkowników (Użytkownik), a także wyszukiwaj ich w bazie po ID, aktualizuj ich dane w bazie, a także usuwaj ich z bazy.
  2. Przypisz użytkownikom obiekty pojazdów (Auto). Twórz, edytuj, wyszukuj i usuwaj samochody z bazy danych.
  3. Dodatkowo aplikacja powinna automatycznie usuwać z bazy samochody „osierocone”. Te. Gdy użytkownik zostanie usunięty, wszystkie należące do niego samochody muszą zostać również usunięte z bazy danych.
Struktura naszego projektu będzie następująca: Twoja pierwsza aplikacja Hibernate — 2Jak widać, nic skomplikowanego. 6 klas + 1 plik z konfiguracjami. Najpierw utwórzmy nowy projekt maven w Intellij Idea. Plik -> Nowy projekt. Z proponowanych typów projektów wybierz Maven i przejdź dalej. Twoja pierwsza aplikacja Hibernate — 3Apache Maven to framework do automatyzacji składania projektów w oparciu o opis ich struktury w plikach w języku POM. Cała struktura Twojego projektu zostanie opisana w pliku pom.xml, który sam IDEA utworzy w katalogu głównym Twojego projektu. W ustawieniach projektu musisz określić parametry Mavena - groupId i artifactId. Zwykle w projektach groupId jest nazwą organizacji lub oddziału i tam zapisana jest nazwa domeny organizacji lub strony projektu. Z kolei artifactId to nazwa projektu. Dla groupdId możesz określić com.вашНикнейм.javarush, nie będzie to miało żadnego wpływu na działanie aplikacji. W polu artifactId wybierz dowolną nazwę projektu. Możesz także pozostawić wersję bez zmian. Twoja pierwsza aplikacja Hibernate — 4Na ostatnim ekranie wystarczy potwierdzić wprowadzone wcześniej dane. Twoja pierwsza aplikacja Hibernate — 5No więc stworzyliśmy projekt, pozostaje tylko napisać kod i sprawić, żeby działał :) Po pierwsze, jeśli chcemy stworzyć aplikację współpracującą z bazą danych, to na pewno nie obejdzie się bez bazy danych! Pobierz stąd PostgreSQL (używam wersji 9). PostgreSQL ma domyślnego użytkownika „postgres”, podczas instalacji będziesz musiał utworzyć dla niego hasło. Nie zapomnij hasła, będzie nam potrzebne później! (Generalnie używanie domyślnej bazy danych w aplikacjach jest złą praktyką, ale aby zmniejszyć ilość hemoroidów, poprzestaniemy na stworzeniu własnej bazy danych). Jeśli nie znasz się na wierszu poleceń i zapytaniach SQL, mamy dobrą wiadomość. Intellij IDEA zapewnia całkiem odpowiedni interfejs użytkownika do pracy z bazą danych. Wygląda to tak: Twoja pierwsza aplikacja Hibernate — 6(znajduje się na prawym pasku bocznym IDEA, zakładka Baza danych) Aby utworzyć połączenie, kliknij „+”, wybierz naszego dostawcę (PostgeSQL). Wypełnij pola nazwą użytkownika, bazą danych (oba są postgres) i wprowadź hasło, które ustawiłeś podczas instalacji PostgreSQL. W razie potrzeby pobierz sterownik Postgres, można to zrobić na tej samej stronie. Kliknij „Testuj połączenie”, aby sprawdzić, czy połączenie z bazą danych zostało nawiązane. Jeśli widzisz napis „Udało się”, przechodzimy dalej. Teraz utwórzmy potrzebne nam tabele. Będzie ich dwóch - użytkowników i automatów. Parametry tabeli użytkowników: Twoja pierwsza aplikacja w Hibernate - 7Należy pamiętać, że identyfikator jest kluczem podstawowym. Jeśli nie wiesz, czym jest klucz podstawowy w SQL, wyszukaj go w Google, to ważne. Ustawienie tabeli autos: Twoja pierwsza aplikacja Hibernate — 8W przypadku samochodów musisz skonfigurować klucz obcy - klucz obcy. Połączy nasze stoły. Radzę przeczytać o nim więcej; Mówiąc najprościej, chodzi o zewnętrzną tabelę, w naszym przypadku użytkowników. Jeśli samochód należy do użytkownika o id=1, to w polu user_id tabeli autos będzie miał wartość 1. W ten sposób łączymy użytkowników z ich samochodami w naszej aplikacji. W naszej tabeli autos pole user_id będzie służyć jako klucz obcy. Będzie odnosić się do pola id tabeli użytkowników. Twoja pierwsza aplikacja Hibernate — 9W ten sposób stworzyliśmy bazę danych zawierającą dwie tabele. Pozostaje zrozumieć, jak zarządzać nim z poziomu kodu Java. Zaczniemy od pliku pom.xml, w którym musimy zawrzeć niezbędne biblioteki (w języku Maven nazywane są one zależnościami). Wszystkie biblioteki przechowywane są w centralnym repozytorium Mavena. Te z nich, które określisz w pom.xml, możesz wykorzystać w projekcie. Twój pom.xml powinien wyglądać tak: Twoja pierwsza aplikacja Hibernate - 10Nic skomplikowanego, jak widzisz. Dodaliśmy tylko 2 zależności - do korzystania z PostgreSQL i Hibernate. Przejdźmy teraz do kodu Java. Utwórz wszystkie niezbędne pakiety i klasy dla projektu. Na początek będziemy potrzebować modeli danych - klas Useri Auto.
package models;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Table (name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    @Column(name = "name")
    private String name;
    //nie możesz określić nazwy kolumny, jeśli pasuje ona do nazwy kolumny w tabeli
    private int age;

    @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Auto> autos;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
        autos = new ArrayList<>();
    }

    public void addAuto(Auto auto) {
        auto.setUser(this);
        autos.add(auto);
    }

    public void removeAuto(Auto auto) {
        autos.remove(auto);
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public List<Auto> getAutos() {
        return autos;
    }

    public void setAutos(List<Auto> autos) {
        this.autos = autos;
    }

    @Override
    public String toString() {
        return "models.User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package models;

import javax.persistence.*;

@Entity
@Table(name = "autos")
public class Auto {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    @Column (name = "model")
    private String model;

    //nie możesz określić nazwy kolumny, jeśli pasuje ona do nazwy kolumny w tabeli
    private String color;


    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    public Auto() {
    }

    public Auto(String model, String color) {
        this.model = model;
        this.color = color;
    }

    public int getId() {
        return id;
    }

    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String toString() {
        return color + " " + model;
    }
}
Jak widać, zajęcia są opatrzone mnóstwem wciąż niejasnych adnotacji. Zacznijmy sobie z nimi radzić. Główną adnotacją dla nas jest @Entity. Poczytaj o tym na Wikipedii i zapamiętaj wszystko, to podstawa. Ta adnotacja umożliwia powiązanie obiektów Java Twojej klasy z bazą danych. Aby klasa była jednostką, musi spełniać następujące wymagania:
  • Musi mieć pusty konstruktor ( publiclub protected);
  • Nie może być zagnieżdżony, interfejsowy ani enum;
  • Nie może być finali nie może zawierać final-pól/właściwości;
  • Musi zawierać co najmniej jedno pole @Id.
Sprawdź swoje klasy jednostek, są to bardzo popularne miejsca, w których można strzelić sobie w stopę. Bardzo łatwo jest o czymś zapomnieć. W takim przypadku podmiot może:
  • Zawierają niepuste konstruktory;
  • Być dziedziczonym i być dziedziczonym;
  • Zawierać inne metody i implementować interfejsy.
Jak widać, klasa ta Userjest bardzo podobna do tabeli users. Istnieją pola id, name, age. Znajdujące się nad nimi adnotacje nie wymagają większego wyjaśnienia: wiadomo już, że @Id jest wskazówką, że pole jest identyfikatorem obiektów tej klasy. Adnotacja @Table nad klasą określa nazwę tabeli, w której zapisywane są obiekty. Zwróć uwagę na komentarz nad polem wieku: jeśli nazwa pola w klasie i tabeli jest taka sama, nie musisz dodawać adnotacji @Column, tak to będzie działać. Jeśli chodzi o „strategię = GenerationType.IDENTITY” wskazaną w nawiasach: istnieje kilka strategii generowania identyfikatora. Możesz to wpisać w Google, ale w ramach naszej aplikacji nie musisz się tym przejmować. Najważniejsze jest to, że identyfikatory dla naszych obiektów będą generowane automatycznie, więc nie ma modułu ustawiającego identyfikator i nie określamy go też w konstruktorze. UserJednak klasa ta nadal wyróżnia się pod pewnymi względami . Ma listę samochodów! Adnotacja @OneToMany pojawi się nad listą. Oznacza to, że jeden obiekt klasy użytkownika może odpowiadać kilku maszynom. Ustawienie „mappedBY” wskazuje na pole użytkownika klasy Auto. W ten sposób maszyny i użytkownicy są ze sobą połączeni. Ustawienie orphanRemoval całkiem dobrze tłumaczy się z angielskiego - „usuń sieroty”. Jeśli usuniemy użytkownika z bazy, wszystkie powiązane z nim samochody również zostaną usunięte. Z kolei na zajęciach Autozobaczysz pole użytkownika z adnotacją @ManyToOne (wiele Auto może odpowiadać jednemu Użytkownikowi) oraz adnotacją @JoinColumn. Wskazuje, przez którą kolumnę w tabeli autos następuje połączenie z tabelą użytkowników (ten sam klucz obcy, o którym mówiliśmy wcześniej). Po stworzeniu modelu danych przychodzi czas na nauczenie naszego programu wykonywania operacji na tych danych w bazie danych. Zacznijmy od klasy narzędziowej HibernateSessionFactoryUtil. Ma tylko jedno zadanie - stworzyć fabrykę sesji, aby nasza aplikacja mogła współpracować z bazą danych (witaj, wzorzec „Factory!”). Nie może zrobić nic innego.
package utils;

import models.Auto;
import models.User;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;

public class HibernateSessionFactoryUtil {
    private static SessionFactory sessionFactory;

    private HibernateSessionFactoryUtil() {}

    public static SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            try {
                Configuration configuration = new Configuration().configure();
                configuration.addAnnotatedClass(User.class);
                configuration.addAnnotatedClass(Auto.class);
                StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties());
                sessionFactory = configuration.buildSessionFactory(builder.build());

            } catch (Exception e) {
                System.out.println("Wyjątek!" + e);
            }
        }
        return sessionFactory;
    }
}
W tej klasie tworzymy nowy obiekt konfiguracyjny Konfiguracja i przekazujemy mu klasy, które powinien postrzegać jako byty - Useroraz Auto. Zwróć uwagę na metodę configuration.getProperties(). Jakie inne właściwości? Gdzie? Właściwości to parametry działania hibernacji, określone w specjalnym pliku hibernate.cfg.xml. Twoja pierwsza aplikacja Hibernate - 11Plik Hibernate.cfg.xml czyta się tutaj: new Configuration().configure(); Jak widać nie ma w nim nic specjalnego - parametry łączenia się z bazą danych oraz specjalny parametr show_sql. Jest to potrzebne, aby wszystkie zapytania SQL, które hibernacja wykona w stosunku do naszej bazy danych, były wysyłane do konsoli. W ten sposób zobaczysz dokładnie, co robi Hibernacja w danym momencie i pozbędziesz się „magicznego” efektu. Następnie potrzebujemy klasy UserDAO. (W dobrym tego słowa znaczeniu trzeba programować poprzez interfejsy - utwórz interfejs UserDAOi osobno go zaimplementuj UserDAOImpl, ale żeby zmniejszyć ilość kodu, pominę to. Nie rób tego w prawdziwych projektach!). DAO (obiekt dostępu do danych) to jeden z najpopularniejszych wzorców projektowych, „Dostęp do danych”. Jego sens jest prosty – stworzyć w aplikacji warstwę odpowiedzialną jedynie za dostęp do danych i nic więcej. Pobierz dane z bazy danych, zaktualizuj dane, usuń dane - i to wszystko. Przeczytaj więcej o DAO, będziesz ich stale używać w swojej pracy. Co może zrobić nasza klasa UserDao? Właściwie, jak wszystkie DAO, może pracować tylko z danymi. Znajdź użytkownika po id, zaktualizuj jego dane, usuń go, wyciągnij listę wszystkich użytkowników z bazy lub zapisz nowego użytkownika w bazie - to cała jego funkcjonalność.
package dao;

import models.Auto;
import models.User;
import org.hibernate.Session;
import org.hibernate.Transaction;
import utils.HibernateSessionFactoryUtil;
import java.util.List;

public class UserDao {

    public User findById(int id) {
        return HibernateSessionFactoryUtil.getSessionFactory().openSession().get(User.class, id);
    }

    public void save(User user) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction tx1 = session.beginTransaction();
        session.save(user);
        tx1.commit();
        session.close();
    }

    public void update(User user) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction tx1 = session.beginTransaction();
        session.update(user);
        tx1.commit();
        session.close();
    }

    public void delete(User user) {
        Session session = HibernateSessionFactoryUtil.getSessionFactory().openSession();
        Transaction tx1 = session.beginTransaction();
        session.delete(user);
        tx1.commit();
        session.close();
    }

    public Auto findAutoById(int id) {
        return HibernateSessionFactoryUtil.getSessionFactory().openSession().get(Auto.class, id);
    }

    public List<User> findAll() {
        List<User> users = (List<User>)  HibernateSessionFactoryUtil.getSessionFactory().openSession().createQuery("From User").list();
        return users;
    }
}
Metody UserDaosą do siebie podobne. W większości z nich za pomocą naszej Fabryki Sesji otrzymujemy obiekt Session (sesję łączącą się z naszą bazą danych), tworzymy pojedynczą transakcję w ramach tej sesji, dokonujemy niezbędnych przekształceń danych, zapisujemy wynik transakcji w bazie danych i zamykamy sesję. Same metody, jak widać, są dość proste. DAO jest „sercem” naszej aplikacji. Nie będziemy jednak tworzyć bezpośrednio DAO i wywoływać jego metod w naszym pliku main(). Cała logika zostanie przeniesiona do pliku UserService.
package services;

import dao.UserDao;
import models.Auto;
import models.User;

import java.util.List;

public class UserService {

    private UserDao usersDao = new UserDao();

    public UserService() {
    }

    public User findUser(int id) {
        return usersDao.findById(id);
    }

    public void saveUser(User user) {
        usersDao.save(user);
    }

    public void deleteUser(User user) {
        usersDao.delete(user);
    }

    public void updateUser(User user) {
        usersDao.update(user);
    }

    public List<User> findAllUsers() {
        return usersDao.findAll();
    }

    public Auto findAutoById(int id) {
        return usersDao.findAutoById(id);
    }


}
Usługa to warstwa danych w aplikacji odpowiedzialna za realizację logiki biznesowej. Jeśli Twój program musi wykonać jakąś logikę biznesową, robi to za pośrednictwem usług. Usługa zawiera wewnątrz siebie UserDaoi wywołuje w swoich metodach metody DAO. Może ci się to wydawać powielaniem funkcji (dlaczego nie po prostu wywoływać metod z obiektu dao), ale przy dużej liczbie obiektów i złożonej logice rozbicie aplikacji na warstwy ma ogromne zalety (jest to dobra praktyka, pamiętaj o tej informacji przez dłuższy czas) przyszłość i przeczytaj o „warstwach aplikacji” „). W naszym serwisie logika jest prosta, jednak w realnych projektach metody obsługi będą zawierać znacznie więcej niż jedną linijkę kodu :) Teraz mamy wszystko co potrzebne do działania aplikacji! Stwórzmy main()dla niego w metodzie użytkownika i maszyny, połączmy je ze sobą i zapiszmy w bazie danych.
import models.Auto;
import models.User;
import services.UserService;

import java.sql.SQLException;

public class Main {
    public static void main(String[] args) throws SQLException {

        UserService userService = new UserService();
        User user = new User("Masha",26);
        userService.saveUser(user);
        Auto ferrari = new Auto("Ferrari", "red");
        ferrari.setUser(user);
        user.addAuto(ferrari);
        Auto ford = new Auto("Ford", "black");
        ford.setUser(user);
        user.addAuto(ford);
        userService.updateUser(user);
    }
}
Jak widać, tabela użytkowników ma swój własny wpis, a tabela autos ma swój własny. Twoja pierwsza aplikacja Hibernate — 13Twoja pierwsza aplikacja Hibernate - 14Spróbujmy zmienić nazwę naszego użytkownika. Wyczyśćmy tabelę użytkowników i uruchommy kod
import models.Auto;
import models.User;
import services.UserService;

import java.sql.SQLException;

public class Main {
    public static void main(String[] args) throws SQLException {

        UserService userService = new UserService();
        User user = new User("Masha",26);
        userService.saveUser(user);
        Auto ferrari = new Auto("Ferrari", "red");
        user.addAuto(ferrari);
        Auto ford = new Auto("Ford", "black");
        ford.setUser(user);
        user.addAuto(ford);
        userService.updateUser(user);
        user.setName("Sasha");
        userService.updateUser(user);
    }
}
Pracuje! Twoja pierwsza aplikacja Hibernate — 15Co się stanie, jeśli usuniesz użytkownika? Wyczyśćmy tabelę użytkowników (automaty wyczyści się same) i wykonajmy kod
import models.Auto;
import models.User;
import services.UserService;

import java.sql.SQLException;

public class Main {
    public static void main(String[] args) throws SQLException {

        UserService userService = new UserService();
        User user = new User("Masha",26);
        userService.saveUser(user);
        Auto ferrari = new Auto("Ferrari", "red");
        user.addAuto(ferrari);
        Auto ford = new Auto("Ford", "black");
        ford.setUser(user);
        user.addAuto(ford);
        userService.updateUser(user);
        user.setName("Sasha");
        userService.updateUser(user);
        userService.deleteUser(user);
    }
}
A nasze tabele są zupełnie puste (zwróć uwagę na konsolę, zostaną tam wyświetlone wszystkie zapytania, które wykonał Hibernacja). Możesz pobawić się aplikacją i wypróbować wszystkie jej funkcje. Przykładowo utwórz użytkownika z maszynami, zapisz go w bazie danych, zobacz jaki jest mu przypisany ID i spróbuj zastosować metodę main()aby „wyciągnąć” użytkownika z bazy po tym id i wyświetlić listę jego maszyn w konsoli . Oczywiście poznaliśmy tylko niewielką część funkcjonalności Hibernate. Jego możliwości są bardzo szerokie i od dawna jest jednym z branżowych standardów programowania w języku Java. Jeśli chcesz przestudiować to szczegółowo, mogę polecić książkę „Java Persistence API and Hibernate”, którą recenzowałem w jednym z moich poprzednich artykułów. Mam nadzieję, że ten artykuł był przydatny dla czytelników. Jeśli masz jakieś pytania, zadaj je w komentarzach, chętnie odpowiem :) Nie zapomnij też wesprzeć autora w konkursie poprzez „polubienie” go. Albo jeszcze lepiej – „Bardzo mi się to podoba” :) Powodzenia na studiach!
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION