CodeGym /Blog Java /Random-PL /Twoja pierwsza aplikacja Hibernate
John Squirrels
Poziom 41
San Francisco

Twoja pierwsza aplikacja Hibernate

Opublikowano w grupie Random-PL
W tym artykule zapoznasz się z jednym z najpopularniejszych frameworków korporacyjnych dla Javy i utworzysz swoją pierwszą aplikację Hibernate. Nigdy nie słyszałeś o Hibernacji? A może o nim słyszałeś, ale nie używałeś? A może próbowałeś go użyć, ale nie udało Ci się? We wszystkich trzech przypadkach - witamy poniżej progu :) Twoja pierwsza aplikacja Hibernate — 1 Witam wszystkich! W tym artykule omówię główne funkcje środowiska Hibernate i pomogę Ci napisać pierwszą miniaplikację. W tym celu potrzebujemy:
  1. IntelliJ IDEA Ultimate Edition
    Pobierz go z oficjalnej strony internetowej i aktywuj 30-dniową wersję próbną.
  2. PostgreSQL - jeden z najpopularniejszych nowoczesnych systemów zarządzania bazami danych (DBMS)
  3. Maven (już podłączony do IDEA)
  4. Trochę cierpliwości.
Na wszelki wypadek umieściłem kod aplikacji na GitHubie (gałąź codegym). Artykuł skierowany jest przede wszystkim do osób, które nigdy wcześniej nie pracowały z tą technologią, więc zminimalizowałem ilość kodu. Zacznijmy!

Co to jest hibernacja?

Jest to jedna z najpopularniejszych implementacji mapowania obiektowo-relacyjnego (ORM). Odwzorowanie obiektowo-relacyjne definiuje relacje między obiektami oprogramowania a rekordami bazy danych. Oczywiście Hibernate ma bardzo szeroką funkcjonalność, ale my skupimy się na najprostszych funkcjach. Naszym celem jest stworzenie aplikacji CRUD (Create, Read, Update, Delete), która będzie mogła:
  1. Twórz użytkowników (Użytkownik), wyszukuj ich w bazie danych po identyfikatorze, aktualizuj ich dane w bazie danych oraz usuwaj ich z bazy danych.
  2. Przypisz użytkownikom obiekty samochodów (Auto). Twórz, aktualizuj, znajduj i usuwaj samochody z bazy danych.
  3. Dodatkowo aplikacja powinna automatycznie usuwać samochody „bez właściciela” z bazy danych. Innymi słowy, po usunięciu użytkownika wszystkie samochody należące do tego użytkownika również muszą zostać usunięte z bazy danych.
Nasz projekt będzie miał następującą strukturę: Twoja pierwsza aplikacja Hibernate - 2Jak widać, nic skomplikowanego. 6 klas + 1 plik z konfiguracjami. Najpierw utwórz nowy projekt Maven w IntelliJ IDEA. Plik -> Nowy projekt. Wybierz Mavena spośród proponowanych typów projektów i przejdź do następnego kroku. Twoja pierwsza aplikacja Hibernate - 3Apache Maven to framework do automatycznego budowania projektów na podstawie opisu ich struktury w plikach POM. Cała struktura Twojego projektu zostanie opisana w pliku pom.xml, który sama IDEA utworzy w katalogu głównym Twojego projektu. W ustawieniach projektu musisz określić następujące ustawienia Mavena: groupId i artefactId. W projektach groupId jest zwykle opisem firmy lub jednostki biznesowej. Nazwa domeny firmy lub strony internetowej może przejść tutaj. Z kolei artefaktId to nazwa projektu. Dla groupdId możesz wprowadzić com.yourNickname.codegym. Nie będzie to miało żadnego wpływu na aplikację. Dla artefaktu wybierz dowolną nazwę projektu. Wersję można pozostawić bez zmian. Twoja pierwsza aplikacja Hibernate — 4Na ostatnim ekranie wystarczy zatwierdzić wprowadzone wcześniej dane.Twoja pierwsza aplikacja Hibernate - 5Stworzyliśmy więc projekt. Teraz pozostaje tylko napisać kod i sprawić, by działał :) Po pierwsze: jeśli chcemy stworzyć aplikację współpracującą z bazą danych, to zdecydowanie nie możemy się obejść bez bazy danych! Pobierz PostgreSQL stąd ( używam wersji 9). PostgreSQL ma domyślnego użytkownika „postgres” — podczas instalacji będziesz musiał wymyślić dla niego hasło. Nie zapomnij hasła. Będziemy go potrzebować później! (Generalnie używanie domyślnej bazy danych w aplikacjach jest złą praktyką, ale zrobimy to, aby zmniejszyć liczbę przyczyn wrzodów, tworząc własną bazę danych). Jeśli nie jesteś przyjacielem wiersza poleceń i zapytań SQL, mamy dobrą wiadomość. IntelliJ IDEA zapewnia całkowicie odpowiedni interfejs użytkownika do pracy z bazą danych. Twoja pierwsza aplikacja Hibernate - 6(znajduje się w prawym okienku IDEA, karta Baza danych). Aby utworzyć połączenie, kliknij „+” i wybierz nasze źródło danych (PostgeSQL). Wypełnij pola dla użytkownika i bazy danych ("postgres" dla obu z nich) i wprowadź hasło, które zostało ustawione podczas instalacji PostgreSQL. W razie potrzeby pobierz sterownik Postgres. Możesz 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 „Udane”, przejdź dalej. Teraz utworzymy potrzebne nam tabele. W sumie będzie ich dwóch: users i autos. Parametry dla tabeli users: Twoja pierwsza aplikacja Hibernate - 7Zauważ, że id jest kluczem podstawowym. Jeśli nie wiesz, jaki jest klucz podstawowy w SQL, poszukaj go w Google. To jest ważne. Ustawienia tabeli autos: Twoja pierwsza aplikacja Hibernate - 8W przypadku tabeli autos należy skonfigurować klucz obcy. Posłuży do połączenia naszych tabel. Polecam poczytać więcej na ten temat. Mówiąc prościej, odwołuje się do zewnętrznej tabeli, w naszym przypadku do użytkowników. Jeśli samochód należy do użytkownika o id = 1, to pole user_id autos będzie równe 1. W ten sposób kojarzymy użytkowników z ich samochodami w naszej aplikacji. W naszej tabeli autos pole user_id będzie działać jako klucz obcy. Odniesie się do pola id tabeli użytkowników. Twoja pierwsza aplikacja Hibernate - 9Stworzyliśmy więc bazę danych z dwiema tabelami. Pozostaje tylko zrozumieć, jak zarządzać nim z poziomu kodu Java. Zaczniemy od pliku pom.xml, w którym musimy zawrzeć potrzebne biblioteki (w Mavenie nazywane są zależnościami). Wszystkie biblioteki są przechowywane w centralnym repozytorium Maven. Biblioteki określone w pliku pom.xml są dostępne do użycia w projekcie. Twój plik pom.xml powinien wyglądać tak: Twoja pierwsza aplikacja Hibernate - 10Nic skomplikowanego, jak widać. 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 w projekcie. Na początek potrzebujemy modelu 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;
     // You can omit the Column attribute if the name property matches the column name in the table
     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;
 
     // You can omit the Column attribute if the name property matches the column name in the table
     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ć, klasy mają wiele niejasnych adnotacji. Zacznijmy się w nich zagłębiać. Dla nas główną adnotacją jest @Entity. Poczytaj o tym na Wikipedii i naucz się wszystkiego na pamięć. To jest podstawa fundacji. Ta adnotacja umożliwia mapowanie obiektów Twojej klasy Java na bazę danych. Aby klasa była bytem, ​​musi spełniać następujące wymagania:
  • Musi mieć pusty konstruktor ( publiclub protected)
  • Nie może być zagnieżdżony, interfejs ani plikenum
  • Nie może być finali nie może mieć finalpól/właściwości
  • Musi mieć 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ć. Ponadto jednostka może wykonać następujące czynności:
  • Może mieć niepuste konstruktory
  • Może dziedziczyć i być dziedziczona
  • Może mieć inne metody i implementować interfejsy.
Jak widać, Userklasa jest bardzo podobna do tabeli users. Ma id, nameiagepola. Adnotacje znajdujące się nad nimi nie wymagają szczególnego wyjaśnienia: jasne jest, że @Id wskazuje, że pole jest identyfikatorem obiektów tej klasy. Adnotacja @Table nad klasą wskazuje nazwę tabeli, w której zapisywane są obiekty. Zwróć uwagę na komentarz nad polem wieku: jeśli nazwa pola w klasie jest taka sama jak nazwa tabeli, możesz pominąć adnotację @Column i zadziała. Co do części wskazanej w nawiasach klamrowych („strategy = GenerationType.IDENTITY”): istnieje kilka strategii generowania identyfikatorów. Możesz je znaleźć w Google, ale w przypadku naszej aplikacji nie musisz się tym przejmować. Najważniejsze jest to, że dla naszych obiektów wartość id będzie generowana automatycznie. W związku z tym nie ma ustawiającego dla id i nie ustawiamy go również w konstruktorze. Jednakże,Userklasa się wyróżnia. Ma listę samochodów! Twoja pierwsza aplikacja Hibernate - 11Adnotacja @OneToMany wisi nad listą. Oznacza to, że temu samemu obiektowi klasy User może odpowiadać kilka samochodów. Element „mappedBy” odnosi się do pola użytkownika klasy Auto. W ten sposób samochody i użytkownicy są ze sobą powiązani. Element orphanRemoval wskazuje, czy zastosować operację usuwania do jednostek, które nie mają już relacji. Jeśli usuniemy użytkownika z bazy danych, to wszystkie samochody z nim powiązane również zostaną usunięte. Z kolei wAutoclass, zobaczysz pole użytkownika z adnotacją @ManyToOne (jeden użytkownik może odpowiadać wielu Autos) i adnotacją @JoinColumn. Wskazuje, która kolumna w tabeli autos jest używana do odniesienia do tabeli users (tzn. klucz obcy, o którym mówiliśmy wcześniej). Po utworzeniu modelu danych przychodzi czas na nauczenie naszego programu wykonywania operacji na danych w bazie danych. Zacznijmy od klasy narzędzia HibernateSessionFactoryUtil. Ma tylko jedno zadanie — stworzyć fabrykę sesji dla naszej aplikacji do pracy z bazą danych (przywitaj się ze wzorcem projektowym Factory!). Nie wie, jak zrobić coś 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("Исключение!" + e);
             }
         }
         return sessionFactory;
     }
 }
 
W tej klasie tworzymy nowy obiekt Configuration i przekazujemy mu klasy, które powinien traktować jako byty: Useri Auto. Zwróć uwagę na configuration.getProperties()metodę. Jakie są inne właściwości? Skąd oni pochodzą? Właściwości to ustawienia hibernacji wskazane w specjalnym pliku hibernate.cfg.xml. Twoja pierwsza aplikacja Hibernate - 12Plik Hibernate.cfg.xml jest odczytywany tutaj: new Configuration().configure(); Jak widać, nie ma w nim nic szczególnego: zawiera parametry połączenia z bazą danych, a także parametr show_sql. Jest to wymagane, aby wszystkie zapytania sql wykonywane przez Hibernate były wyświetlane na konsoli. W ten sposób zobaczysz dokładnie, co Hibernate robi w danym momencie, eliminując wszelkie poczucie „magii”. Następnie potrzebujemyUserDAOklasa. Najlepszą praktyką jest programowanie przez interfejsy — stwórz osobny UserDAOinterfejs i UserDAOImplimplementację, ale pominę to, aby zmniejszyć ilość kodu. Nie rób tego w prawdziwych projektach! Wzorzec projektowy DAO (obiekt dostępu do danych) jest jednym z najbardziej powszechnych. Pomysł jest prosty — stworzyć warstwę aplikacji odpowiedzialną tylko za dostęp do danych, nic więcej. Pobieranie danych z bazy danych, aktualizowanie danych, usuwanie danych — to wszystko. Dowiedz się więcej o DAO. W swojej pracy będziesz stale korzystać z obiektów dostępu do danych. Co potrafi nasza UserDaoklasa? Cóż, jak wszystkie DAO, może działać tylko z danymi. Znajdź użytkownika po identyfikatorze, zaktualizuj jego dane, usuń go, pobierz listę wszystkich użytkowników z bazy danych lub zapisz nowego użytkownika w bazie danych — 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;
     }
 }
 
UserDaometody są do siebie podobne. W większości z nich uzyskujemy obiekt Session (sesja połączenia z bazą danych) za pomocą naszej Fabryki Sesji, tworzymy pojedynczą transakcję w ramach tej sesji, wykonujemy niezbędne manipulacje danymi, zapisujemy wynik transakcji w bazie danych, a następnie zamykamy sesję. Same metody, jak widać, są dość proste. DAO to „serce” naszej aplikacji. Jednak nie stworzymy bezpośrednio DAO i nie wywołamy jego metod w naszej main()metodzie. Cała logika zostanie przeniesiona do UserServiceklasy.

 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 aplikacji odpowiedzialna za wykonywanie logiki biznesowej. Jeśli twój program musi wykonać jakąś logikę biznesową, robi to za pośrednictwem usług. Usługa zawiera UserDaoi wywołuje metody DAO w swoich metodach. Może się wydawać, że duplikujemy tutaj funkcje (dlaczego po prostu nie wywołać metod z obiektu DAO?), ale przy wielu obiektach i złożonej logice nakładanie aplikacji na warstwy zapewnia ogromne korzyści (jest to dobra praktyka — pamiętaj o tym w przyszłości) i przeczytaj o „warstwach aplikacji”). Nasz serwis ma prostą logikę, ale metody serwisowe w rzeczywistych projektach zawierają znacznie więcej niż jedną linię kodu :) Teraz mamy wszystko, czego potrzebujesz do uruchomienia aplikacji! W main()metodzie utwórzmy użytkownika i jego samochód, powiążmy 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 ("Jenny", 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 users ma swój własny rekord, a tabela autos ma swój własny rekord. Twoja pierwsza aplikacja Hibernate - 13Twoja pierwsza aplikacja Hibernate - 14Spróbujmy zmienić nazwę naszego użytkownika. Wyczyść tabelę użytkowników i wykonaj 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 ("Jenny", 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 ("Benny");
         userService.updateUser(user);
     }
 }
 
 
To działa! Twoja pierwsza aplikacja Hibernate - 15Co się stanie, jeśli usuniesz użytkownika? Wyczyść tabelę użytkowników (autos sam się wyczyści) i wykonaj 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 ("Jenny", 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 ("Benny");
         userService.updateUser(user);
         userService.deleteUser(user);
     }
 }
 
 
A nasze tabele są zupełnie puste (zwróć uwagę na konsolę — będą tam wyświetlane wszystkie żądania wykonywane przez Hibernate). Możesz bawić się aplikacją i wypróbować wszystkie jej funkcje. Na przykład utwórz użytkownika z samochodami, zapisz go w bazie danych, spójrz na identyfikator przypisany do użytkownika i spróbuj użyć tego identyfikatora wmain()sposób na pobranie użytkownika z bazy danych i wyświetlenie listy jego samochodów na konsoli. Oczywiście widzieliśmy tylko niewielką część funkcjonalności Hibernate. Jego możliwości są bardzo szerokie i od dawna jest standardowym narzędziem branżowym do programowania w Javie. Jeśli chcesz to szczegółowo przestudiować, mogę polecić książkę „Java Persistence API and Hibernate”. Recenzowałem w poprzednim artykule. Mam nadzieję, że ten artykuł był pomocny dla czytelników. Jeśli masz pytania, zadaj je w komentarzach. Chętnie odpowiem :) Nie zapomnijcie również wesprzeć autora w konkursie poprzez wstawienie "Lubię to". Albo jeszcze lepiej — „Love it” :) Powodzenia w nauce!
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION