In dit artikel maakt u kennis met een van de meest populaire enterprise-frameworks voor Java en maakt u uw eerste Hibernate-toepassing. Nog nooit van Hibernate gehoord? Of misschien heb je er wel eens van gehoord, maar nog niet gebruikt? Of misschien heb je geprobeerd het te gebruiken, maar is het niet gelukt? In alle drie de gevallen - welkom onder de snit :) Hallo allemaal! In dit artikel zal ik het hebben over de belangrijkste functies van het Hibernate-framework en zal ik je helpen bij het schrijven van je eerste mini-applicatie. Hiervoor hebben we nodig:
- IntelliJ IDEA Ultimate Edition
Download het van de officiële website en activeer de proefversie van 30 dagen. - PostgreSQL - een van de meest populaire moderne databasebeheersystemen (DBMS)
- Maven (al aangesloten op IDEA)
- Een beetje geduld.
Wat is overwinteren?
Het is een van de meest populaire ORM-implementaties (Object-Relational Mapping). Een object-relationele mapping definieert de relatie tussen software-objecten en databaserecords. Natuurlijk heeft Hibernate een zeer brede functionaliteit, maar we zullen ons concentreren op de eenvoudigste functies. Ons doel is om een CRUD-applicatie (Create, Read, Update, Delete) te maken die in staat zal zijn om:- Maak gebruikers aan (User), zoek ze in de database op ID, update hun gegevens in de database en verwijder ze uit de database.
- Wijs auto-objecten (Auto) toe aan gebruikers. Maak, update, zoek en verwijder auto's uit de database.
- Bovendien zou de applicatie auto's zonder eigenaar automatisch uit de database moeten verwijderen. Met andere woorden, wanneer een gebruiker wordt verwijderd, moeten ook alle auto's van die gebruiker uit de database worden verwijderd.
com.yourNickname.codegym
. Dit heeft geen invloed op de toepassing. Kies voor artefactId een gewenste projectnaam. De versie kan ongewijzigd worden gelaten. Op het laatste scherm bevestigt u eenvoudig de eerder ingevoerde gegevens.Dus hebben we het project gemaakt. Nu rest ons alleen nog wat code te schrijven en het te laten werken :) Allereerst: als we een applicatie willen maken die met een database werkt, kunnen we zeker niet zonder een database! Download PostgreSQL hier (ik gebruik versie 9). PostgreSQL heeft een standaardgebruiker 'postgres' - u moet er een wachtwoord voor bedenken tijdens de installatie. Vergeet het wachtwoord niet. We hebben het later nodig! (Over het algemeen is het gebruik van de standaarddatabase in toepassingen een slechte gewoonte, maar we doen dit om het aantal oorzaken van zweren te verminderen door uw eigen database te maken). Als u geen vrienden bent met de opdrachtregel en SQL-query's, is er goed nieuws. IntelliJ IDEA biedt een geheel geschikte gebruikersinterface voor het werken met de database. (bevindt zich in het rechterdeelvenster van IDEA, het tabblad Database). Om een verbinding tot stand te brengen, klikt u op "+" en selecteert u onze gegevensbron (PostgeSQL). Vul de velden in voor de gebruiker en de database ("postgres" voor beide) en voer het wachtwoord in dat is ingesteld tijdens de installatie van PostgreSQL. Download indien nodig het Postgres-stuurprogramma. Dit doe je op dezelfde pagina. Klik op "Test Connection" om te controleren of de databaseverbinding tot stand is gebracht. Als je "Succesvol" ziet, ga dan verder. Nu gaan we de tabellen maken die we nodig hebben. Er zullen er in totaal twee zijn: gebruikers en auto's. Parameters voor de gebruikerstabel: Merk op dat id de primaire sleutel is. Als u niet weet wat de primaire sleutel is in SQL, Google het dan. Dit is belangrijk. Instellingen voor automatische tabel: Voor de autos-tabel moet u een externe sleutel configureren. Het zal dienen om onze tabellen te koppelen. Ik raad je aan er meer over te lezen. Simpel gezegd, het verwijst naar een externe tabel, in ons geval gebruikers. Als een auto van de gebruiker is met id = 1, dan is het veld user_id van de auto's gelijk aan 1. Op deze manier associëren we gebruikers met hun auto's in onze applicatie. In onze autos-tabel fungeert het veld user_id als externe sleutel. Het zal verwijzen naar het id-veld van de gebruikerstabel. We hebben dus een database gemaakt met twee tabellen. Wat overblijft, is begrijpen hoe het vanuit Java-code moet worden beheerd. We beginnen met het bestand pom.xml, waarin we de benodigde bibliotheken moeten opnemen (in Maven worden ze afhankelijkheden genoemd). Alle bibliotheken worden opgeslagen in de centrale Maven-repository. De bibliotheken die u opgeeft in pom.xml zijn beschikbaar voor gebruik in het project. Uw pom.xml zou er zo uit moeten zien: Niets ingewikkelds, zoals u kunt zien. We hebben slechts 2 afhankelijkheden toegevoegd - voor het gebruik van PostgreSQL en Hibernate. Laten we nu verder gaan met de Java-code. Maak alle benodigde pakketten en klassen in het project. Om te beginnen hebben we een gegevensmodel nodig: de klassen User
en .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;
}
}
Zoals je kunt zien, hebben klassen een aantal obscure annotaties. Laten we beginnen met ze in te graven. Voor ons is de belangrijkste annotatie @Entity. Lees erover op Wikipedia en leer het allemaal uit je hoofd. Dit is de basis van de stichting. Met deze annotatie kunnen objecten van uw Java-klasse worden toegewezen aan een database. Om een klasse een entiteit te laten zijn, moet deze aan de volgende vereisten voldoen:
- Het moet een lege constructor hebben (
public
ofprotected
) - Het kan niet worden genest, een interface of een
enum
- Het kan en kan geen velden/eigenschappen
final
hebbenfinal
- Het moet ten minste één @Id-veld hebben.
- Het kan niet-lege constructors hebben
- Het kan erven en geërfd worden
- Het kan andere methoden hebben en interfaces implementeren.
User
lijkt de klasse erg op de gebruikerstabel. Het heeft id
, name
, enage
velden. De annotaties die erboven staan hebben geen specifieke uitleg nodig: het is duidelijk dat @Id aangeeft dat het veld een identifier is van objecten van deze klasse. De @Table-annotatie boven de klasse geeft de naam aan van de tabel waarin de objecten zijn geschreven. Let op de opmerking boven het leeftijdsveld: als de naam van het veld in de klas hetzelfde is als de naam van de tabel, kunt u de @Column-annotatie weglaten en het zal werken. Wat betreft het deel dat tussen de accolades staat ("strategy = GenerationType.IDENTITY"): er zijn verschillende strategieën om ID's te genereren. U kunt ze googlen, maar voor onze toepassing hoeft u zich geen zorgen te maken. Het belangrijkste is dat voor onze objecten de waarde van id automatisch wordt gegenereerd. Dienovereenkomstig is er geen setter voor id, en we stellen het ook niet in de constructor in. Echter,User
klasse springt er uit. Het heeft een lijst met auto's! De annotatie @OneToMany hangt boven de lijst. Dit betekent dat meerdere auto's kunnen overeenkomen met hetzelfde object van de User-klasse. Het element "mappedBy" verwijst naar het gebruikersveld van de Auto
klasse. Auto's en gebruikers zijn dus aan elkaar gerelateerd. Het element weesRemoval geeft aan of de verwijderbewerking moet worden toegepast op entiteiten die geen relatie meer hebben. Als we een gebruiker uit de database verwijderen, worden ook alle auto's die eraan gekoppeld zijn verwijderd. Op zijn beurt in deAuto
class, ziet u het gebruikersveld met de @ManyToOne-annotatie (één gebruiker kan overeenkomen met veel Auto's) en de @JoinColumn-annotatie. Het geeft aan welke kolom in de autos-tabel wordt gebruikt om naar de gebruikerstabel te verwijzen (dwz de externe sleutel waar we het eerder over hadden). Nadat het datamodel is gemaakt, is het tijd om ons programma te leren bewerkingen uit te voeren met de gegevens in de database. Laten we beginnen met de klasse HibernateSessionFactoryUtil. Het heeft maar één taak: een sessiefabriek maken zodat onze applicatie met de database kan werken (zeg hallo tegen het Factory-ontwerppatroon!). Het weet niet hoe het anders moet.
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;
}
}
In deze klasse maken we een nieuw configuratieobject en geven het de klassen door die het als entiteiten moet behandelen: User
en Auto
. Let op de configuration.getProperties()
methode. Welke andere eigenschappen zijn er? Waar komen ze vandaan? Eigenschappen zijn de slaapstandinstellingen die worden aangegeven in het speciale bestand hibernate.cfg.xml. Hibernate.cfg.xml wordt hier gelezen: new Configuration().configure();
Zoals u ziet, is er niets bijzonders aan: het bevat de parameters voor verbinding met de database, evenals de parameter show_sql. Dit is vereist zodat alle sql-query's die door Hibernate worden uitgevoerd, op de console worden weergegeven. Op deze manier zie je precies wat Hibernate op een bepaald moment aan het doen is, en elimineer je elk gevoel van "magie". Vervolgens hebben we deUserDAO
klas. De beste praktijk is om via de interfaces te programmeren — maak een aparte UserDAO
interface en UserDAOImpl
implementatie, maar ik zal dit overslaan om de hoeveelheid code te verminderen. Doe dit niet in echte projecten! Het DAO-ontwerppatroon (data access object) is een van de meest voorkomende. Het idee is eenvoudig: maak een applicatielaag die alleen verantwoordelijk is voor toegang tot gegevens, niets meer. Gegevens ophalen uit de database, gegevens bijwerken, gegevens verwijderen - dat is alles. Lees meer over DAO. In uw werk gebruikt u voortdurend objecten voor gegevenstoegang. Wat kan onze UserDao
klas doen? Zoals alle DAO's kan het alleen met gegevens werken. Zoek een gebruiker op id, werk de gegevens bij, verwijder deze, haal een lijst op met alle gebruikers uit de database of sla een nieuwe gebruiker op in de database - dat is de volledige functionaliteit.
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
De methodes lijken op elkaar. In de meeste daarvan krijgen we een Session- object (databaseverbindingssessie) met behulp van onze Session Factory, maken we een enkele transactie binnen deze sessie, voeren we de nodige gegevensmanipulaties uit, slaan we het resultaat van de transactie op in de database en sluiten we de sessie. De methoden zelf zijn, zoals u kunt zien, vrij eenvoudig. DAO is het "hart" van onze applicatie. We zullen echter niet rechtstreeks een DAO maken en de methoden ervan in onze main()
methode aanroepen. Alle logica wordt verplaatst naar de UserService
klasse.
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);
}
}
Een service is een applicatiegegevenslaag die verantwoordelijk is voor het uitvoeren van bedrijfslogica. Als uw programma een soort bedrijfslogica moet uitvoeren, gebeurt dit via services. Een service bevat een UserDao
en roept DAO-methoden op in zijn methoden. Het lijkt misschien alsof we hier functies dupliceren (waarom de methoden niet gewoon vanuit een DAO-object aanroepen?), maar met veel objecten en complexe logica biedt het aanbrengen van lagen enorme voordelen (dit is een goede gewoonte - onthoud dit in de toekomst en lees over "applicatielagen"). Onze service heeft eenvoudige logica, maar servicemethoden in real-world projecten bevatten veel meer dan één regel code :) Nu hebben we alles wat je nodig hebt om de applicatie uit te voeren! main()
Laten we in de methode een gebruiker en zijn auto maken, de ene aan de andere koppelen en deze in de database opslaan.
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);
}
}
Zoals u kunt zien, heeft de gebruikerstabel zijn eigen record en de autos-tabel heeft zijn eigen record. Laten we proberen onze gebruiker een andere naam te geven. Wis de gebruikerstabel en voer de code uit
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);
}
}
Het werkt! Wat als u de gebruiker verwijdert? Wis de gebruikerstabel (auto's wissen zichzelf) en voer de code uit
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);
}
}
En onze tabellen zijn helemaal leeg (let op de console - alle verzoeken die door Hibernate worden uitgevoerd, worden daar weergegeven). Je kunt spelen met de applicatie en alle functies uitproberen. Maak bijvoorbeeld een gebruiker aan met auto's, sla deze op in de database, kijk naar de id die aan de gebruiker is toegewezen en probeer deze id te gebruiken in demain()
methode om de gebruiker uit de database op te halen en een lijst met zijn auto's op de console weer te geven. Natuurlijk hebben we maar een klein deel van de functionaliteit van Hibernate gezien. De mogelijkheden zijn zeer breed en het is lange tijd een standaard industrietool geweest voor Java-ontwikkeling. Als je het in detail wilt bestuderen, kan ik het boek "Java Persistence API and Hibernate" aanbevelen. Ik besprak in een eerder artikel. Ik hoop dat dit artikel nuttig is geweest voor de lezers. Als je vragen hebt, stel ze dan in de comments. Ik zal graag antwoorden :) Vergeet ook niet de auteur in de wedstrijd te steunen door een "Vind ik leuk" te plaatsen. Of beter nog — "Love it" :) Veel succes met je studie!
GO TO FULL VERSION