В тази статия ще се запознаете с една от най-популярните корпоративни рамки за Java и ще създадете първото си приложение Hibernate. Никога не сте чували за Hibernate? Или може би сте чували за него, но не сте го използвали? Или може би сте се опитали да го използвате, но неуспешно? И в трите случая - добре дошли в under the cut :)
Здравейте на всички! В тази статия ще говоря за основните характеристики на рамката Hibernate и ще ви помогна да напишете първото си мини-приложение. За целта се нуждаем от:
Както виждате, нищо сложно. 6 класа + 1 файл с конфигурации. Първо създайте нов проект на Maven в IntelliJ IDEA. Файл -> Нов проект. Изберете Maven от предложените типове проекти и преминете към следващата стъпка.
Apache Maven е рамка за автоматично изграждане на проекти въз основа на описание на тяхната структура в POM файлове. Цялата структура на вашия проект ще бъде описана в pom.xml, файл, който самата IDEA ще създаде в корена на вашия проект. В настройките на проекта трябва да зададете следните настройки на Maven: groupId и artifactId. В проекти groupId обикновено е описание на компанията or бизнес единицата. Името на домейна на компанията or уебсайта може да отиде тук. От своя страна artifactId е името на проекта. За groupdId можете да въведете
На последния екран просто потвърдете въведените преди това данни.
И така, създадохме проекта. Сега всичко, което остава да направите, е да напишете малко code и да го накарате да работи :) Първо: ако искаме да създадем приложение, което работи с база данни, определено не можем без база данни! Изтеглете PostgreSQL от тук (използвам version 9). PostgreSQL има потребител по подразбиране 'postgres' — ще трябва да измислите парола за него, когато инсталирате. Не забравяйте паролата. Ще ни трябва по-късно! (По принцип използването на базата данни по подразбиране в applicationsта е лоша практика, но ние ще го направим, за да намалим броя на причините за язви, като създадем ваша собствена база данни). Ако не сте приятели с командния ред и SQL заявките, има добри новини. IntelliJ IDEA предоставя напълно подходящ потребителски интерфейс за работа с базата данни.
(разположен в десния панел на IDEA, раздел База данни). За да създадете връзка, щракнете върху „+“ и изберете нашия източник на данни (PostgeSQL). Попълнете полетата за потребителя и базата данни ("postgres" и за двете) и въведете паролата, зададена по време на инсталирането на PostgreSQL. Ако е необходимо, изтеглете драйвера на Postgres. Можете да направите това на същата page. Щракнете върху „Тест на връзката“, за да проверите дали връзката с базата данни е установена. Ако видите „Успешно“, продължете напред. Сега ще създадем таблиците, от които се нуждаем. Ще има общо две: потребители и автомобor. Параметри за tableта потребители:
Обърнете внимание, че id е първичният ключ. Ако не знаете Howъв е първичният ключ в SQL, потърсете го в Google. Това е важно. Настройки за tableта с автомати:
За tableта autos трябва да конфигурирате външен ключ. Той ще служи за свързване на нашите маси. Препоръчвам ви да прочетете повече за това. Казано по-просто, той препраща към външна table, в нашия случай потребители. Ако кола принадлежи на потребител с id = 1, тогава полето user_id на автомобorте ще бъде равно на 1. Това е начинът, по който свързваме потребителите с техните автомобor в нашето приложение. В нашата table autos полето user_id ще действа като външен ключ. Той ще препраща към полето за идентификатор на tableта с потребители.
И така, създадохме база данни с две таблици. Остава да разберем How да го управляваме от Java code. Ще започнем с file pom.xml, в който трябва да включим необходимите библиотеки (в Maven те се наричат dependencies). Всички библиотеки се съхраняват в централното хранorще на Maven. Библиотеките, които посочите в pom.xml, са достъпни за използване в проекта. Вашият pom.xml трябва да изглежда така:
Нищо сложно, Howто виждате. Добавихме само 2 зависимости — за използване на PostgreSQL и Hibernate. Сега нека да преминем към Java codeа. Създайте всички необходими пакети и класове в проекта. За да започнем, имаме нужда от модел на данни: класовете
Анотацията @OneToMany виси над списъка. Това означава, че няколко коли могат да съответстват на един и същ обект от класа User. Елементът "mappedBy" се отнася до потребителското поле на
Hibernate.cfg.xml се чете тук: ![Вашето първо приложение Hibernate - 13]()
Нека се опитаме да преименуваме нашия потребител. Изчистете tableта с потребители и изпълнете codeа
Ами ако изтриете потребителя? Изчистете tableта с потребители (autos ще се изчисти сама) и изпълнете codeа

- IntelliJ IDEA Ultimate Edition
Изтеглете го от официалния уебсайт и активирайте 30-дневната пробна version. - PostgreSQL - една от най-популярните съвременни системи за управление на бази данни (СУБД)
- Maven (вече е свързан към IDEA)
- Малко търпение.
Какво е Hibernate?
Това е една от най-популярните реализации на обектно-релационно картографиране (ORM). Обектно-релационното съпоставяне дефинира връзката между софтуерните обекти и записите в базата данни. Разбира се, Hibernate има много широка функционалност, но ние ще се съсредоточим върху най-простите функции. Нашата цел е да създадем CRUD (Създаване, четене, актуализиране, изтриване) приложение, което ще може:- Създавайте потребители (User), търсете ги в базата данни по ID, актуализирайте данните им в базата данни и ги изтривайте от базата данни.
- Присвояване на автомобилни обекти (Авто) на потребителите. Създавайте, актуализирайте, намирайте и изтривайте автомобor от базата данни.
- Освен това приложението трябва автоматично да премахва "безстопанствените" автомобor от базата данни. С други думи, когато даден потребител бъде изтрит, всички автомобor, принадлежащи на този потребител, също трябва да бъдат изтрити от базата данни.


com.yourNickname.codegym
. Това няма да има ефект върху приложението. За artifactId изберете произволно име на проект, което харесвате. Версията може да остане непроменена. 






User
and 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;
}
}
Както можете да видите, класовете имат куп неясни анотации. Нека започнем да се ровим в тях. За нас основната анотация е @Entity. Прочетете за това в Wikipedia и го научете всичко наизуст. Това е основата на основата. Тази анотация позволява обекти от вашия Java клас да бъдат картографирани към база данни. За да бъде един клас обект, той трябва да отговаря на следните изисквания:
- Трябва да има празен конструктор (
public
orprotected
) - Не може да бъде вложен, интерфейс or
enum
- Не може да бъде
final
и не може да имаfinal
полета/свойства - Трябва да има поне едно поле @Id.
- Може да има непразни конструктори
- Може да се наследява и да се наследява
- Може да има други методи и да реализира интерфейси.
User
класът е много подобен на tableта на потребителите. Има id
, name
, иage
полета. Анотациите, разположени над тях, не се нуждаят от специално обяснение: ясно е, че @Id показва, че полето е идентификатор на обекти от този клас. Анотацията @Table над класа показва името на tableта, където са записани обектите. Обърнете внимание на коментара над полето за възраст: ако името на полето в класа е същото като името на tableта, можете да пропуснете анотацията @Column и тя ще работи. Що се отнася до частта, посочена в скобите ("strategy = GenerationType.IDENTITY"): има няколко стратегии за генериране на идентификатори. Можете да ги Google, но за нашето приложение, няма нужда да се притеснявате. Основното е, че за нашите обекти стойността на id ще се генерира автоматично. Съответно няма настройка за id и не го задаваме и в конструктора. Въпреки това,User
класът се откроява. Има списък с автомобor! 
Auto
класа. По този начин автомобorте и потребителите са свързани. Елементът orphanRemoval показва дали да се приложи операцията за премахване към обекти, които вече нямат връзка. Ако изтрием потребител от базата данни, всички автомобor, свързани с него, също ще бъдат изтрити. На свой ред вAuto
клас, ще видите потребителското поле с анотацията @ManyToOne (един потребител може да съответства на много Autos) и анотацията @JoinColumn. Той показва коя колона в tableта autos се използва за препратка към tableта потребители (т.е. чуждия ключ, за който говорихме по-рано). След като създадем модела на данни, е време да научим нашата програма да извършва операции с данните в базата данни. Нека започнем с помощния клас HibernateSessionFactoryUtil. Той има само една задача — да създаде фабрика за сесии за нашето приложение, за да работи с базата данни (кажи здравей на шаблона за проектиране Factory!). То не знае How да прави нищо друго.
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;
}
}
В този клас създаваме нов конфигурационен обект и му предаваме класовете, които трябва да третира като обекти: User
и Auto
. Обърнете внимание на configuration.getProperties()
метода. Какви други имоти има? Откъде идват? Свойствата са настройките за хибернация, посочени в специалния файл hibernate.cfg.xml. 
new Configuration().configure();
Както виждате, в него няма нищо особено: той съдържа параметрите за свързване към базата данни, Howто и параметъра show_sql. Това е необходимо, така че всички sql заявки, изпълнени от Hibernate, да се показват на конзолата. По този начин ще видите точно Howво прави Hibernate във всеки един момент, елиминирайки всяHowво усещане за "магия". След това се нуждаем отUserDAO
клас. Най-добрата практика е да програмирате чрез интерфейсите — създайте отделен UserDAO
интерфейс и UserDAOImpl
реализация, но ще пропусна това, за да намаля количеството code. Не правете това в реални проекти! Шаблонът за проектиране DAO (обект за достъп до данни) е един от най-често срещаните. Идеята е проста - създайте приложен слой, отговорен само за достъп до данни, нищо повече. Извличане на данни от базата данни, актуализиране на данни, изтриване на данни — това е всичко. Проучете повече за DAO. Ще използвате постоянно обекти за достъп до данни в работата си. Какво може да направи нашият UserDao
клас? Е, Howто всички DAO, той може да работи само с данни. Намерете потребител по id, актуализирайте данните му, изтрийте го, вземете списък с всички потребители от базата данни or запишете нов потребител в базата данни — това е цялата му функционалност.
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
Методите на са подобни един на друг. В повечето от тях получаваме обект на сесия (сесия за връзка с базата данни), използвайки нашата фабрика за сесии, създаваме една транзакция в рамките на тази сесия, извършваме необходимите манипулации с данни, запазваме резултата от транзакцията в базата данни и след това затваряме сесията. Самите методи, Howто можете да видите, са доста прости. DAO е „сърцето“ на нашето приложение. Ние обаче няма да създаваме директно DAO и да извикваме неговите методи в нашия main()
метод. Цялата логика ще бъде преместена в 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);
}
}
Услугата е слой от данни на приложението, отговорен за изпълнението на бизнес логиката. Ако вашата програма трябва да изпълни няHowва бизнес логика, тя го прави чрез услуги. Услугата съдържа UserDao
и извиква DAO методи в своите методи. Може да изглежда, че дублираме функции тук (защо просто не извикаме методите от DAO обект?), но с много обекти и сложна логика, наслояването на приложението предоставя огромни предимства (да го правите е добра практика – запомнете това в бъдеще и прочетете за "слоеве на приложение"). Нашата услуга има проста логика, но методите на услугата в проекти от реалния свят съдържат много повече от един ред code :) Сега имаме всичко необходимо, за да стартирате приложението! В main()
метода нека създадем потребител и неговата кола, да ги асоциираме един с друг и да ги запазим в базата данни.
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);
}
}
Както можете да видите, tableта users има свой собствен запис, а tableта autos има свой собствен запис. 

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);
}
}
Работи! 
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);
}
}
И нашите таблици са напълно празни (обърнете внимание на конзолата - всички заявки, извършени от Hibernate, ще бъдат показани там). Можете да си поиграете с приложението и да изпробвате всички негови функции. Например, създайте потребител с автомобor, запазете го в базата данни, погледнете идентификатора, присвоен на потребителя, и опитайте да използвате този идентификатор вmain()
метод за извличане на потребителя от базата данни и показване на списък с неговите коли на конзолата. Разбира се, видяхме само малка част от функционалността на Hibernate. Неговите възможности са много широки и отдавна е standardн индустриален инструмент за разработка на Java. Ако искате да го проучите подробно, мога да препоръчам книгата "Java Persistence API and Hibernate". Прегледах в предишна статия. Надявам се, че тази статия е била полезна за читателите. Ако имате въпроси, задайте ги в коментарите. Ще се радвам да отговоря :) Освен това не забравяйте да подкрепите автора в конкурса, като публикувате „Харесва ми“. Или още по-добре — „Love it“ :) Успех в обучението!
GO TO FULL VERSION