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 :)
Witam wszystkich! W tym artykule omówię główne funkcje środowiska Hibernate i pomogę Ci napisać pierwszą miniaplikację. W tym celu potrzebujemy:
Jak 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.
Apache 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ć
Na ostatnim ekranie wystarczy zatwierdzić wprowadzone wcześniej dane.
Stworzyliś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.
(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:
Zauważ, ż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:
W 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.
Stworzyliś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:
Nic 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
Adnotacja @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
Plik Hibernate.cfg.xml jest odczytywany tutaj: ![Twoja pierwsza aplikacja Hibernate - 13]()
Spróbujmy zmienić nazwę naszego użytkownika. Wyczyść tabelę użytkowników i wykonaj kod
Co się stanie, jeśli usuniesz użytkownika? Wyczyść tabelę użytkowników (autos sam się wyczyści) i wykonaj kod

- IntelliJ IDEA Ultimate Edition
Pobierz go z oficjalnej strony internetowej i aktywuj 30-dniową wersję próbną. - PostgreSQL - jeden z najpopularniejszych nowoczesnych systemów zarządzania bazami danych (DBMS)
- Maven (już podłączony do IDEA)
- Trochę cierpliwości.
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:- 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.
- Przypisz użytkownikom obiekty samochodów (Auto). Twórz, aktualizuj, znajduj i usuwaj samochody z bazy danych.
- 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.


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. 






User
i 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 (
public
lubprotected
) - Nie może być zagnieżdżony, interfejs ani plik
enum
- Nie może być
final
i nie może miećfinal
pól/właściwości - Musi mieć co najmniej jedno pole @Id.
- Może mieć niepuste konstruktory
- Może dziedziczyć i być dziedziczona
- Może mieć inne metody i implementować interfejsy.
User
klasa jest bardzo podobna do tabeli users. Ma id
, name
iage
pola. 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,User
klasa się wyróżnia. Ma listę samochodów! 
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 wAuto
class, 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: User
i 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. 
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 potrzebujemyUserDAO
klasa. Najlepszą praktyką jest programowanie przez interfejsy — stwórz osobny UserDAO
interfejs i UserDAOImpl
implementację, 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 UserDao
klasa? 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;
}
}
UserDao
metody 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 UserService
klasy.
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 UserDao
i 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. 

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! 
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!
GO TO FULL VERSION