In diesem Artikel lernen Sie eines der beliebtesten Enterprise-Frameworks für Java kennen und erstellen Ihre erste Hibernate-Anwendung. Noch nie von Hibernate gehört? Oder vielleicht haben Sie davon gehört, es aber noch nicht genutzt? Oder haben Sie vielleicht versucht, es zu verwenden, sind aber gescheitert? In allen drei Fällen – willkommen unter dem Schnitt :) Hallo zusammen! In diesem Artikel werde ich über die Hauptfunktionen des Hibernate-Frameworks sprechen und Ihnen beim Schreiben Ihrer ersten Minianwendung helfen. Dazu benötigen wir:
- IntelliJ IDEA Ultimate Edition
Laden Sie es von der offiziellen Website herunter und aktivieren Sie die 30-Tage-Testversion. - PostgreSQL – eines der beliebtesten modernen Datenbankverwaltungssysteme (DBMS)
- Maven (bereits mit IDEA verkabelt)
- Ein bisschen Geduld.
Was ist Ruhezustand?
Es handelt sich um eine der beliebtesten ORM-Implementierungen (Object-Relational Mapping). Eine objektrelationale Zuordnung definiert die Beziehung zwischen Softwareobjekten und Datenbankdatensätzen. Natürlich verfügt Hibernate über einen sehr breiten Funktionsumfang, wir konzentrieren uns jedoch auf die einfachsten Funktionen. Unser Ziel ist es, eine CRUD-Anwendung (Erstellen, Lesen, Aktualisieren, Löschen) zu erstellen, die Folgendes kann:- Erstellen Sie Benutzer (Benutzer), suchen Sie sie in der Datenbank anhand ihrer ID, aktualisieren Sie ihre Daten in der Datenbank und löschen Sie sie aus der Datenbank.
- Weisen Sie Benutzern Autoobjekte (Auto) zu. Erstellen, aktualisieren, suchen und löschen Sie Autos aus der Datenbank.
- Darüber hinaus sollte die Anwendung „besitzerlose“ Autos automatisch aus der Datenbank entfernen. Mit anderen Worten: Wenn ein Benutzer gelöscht wird, müssen auch alle zu diesem Benutzer gehörenden Autos aus der Datenbank gelöscht werden.
com.yourNickname.codegym
. Dies hat keine Auswirkungen auf die Anwendung. Wählen Sie als Artefakt-ID einen beliebigen Projektnamen aus. Die Version kann unverändert bleiben. Auf dem letzten Bildschirm bestätigen Sie einfach die zuvor eingegebenen Daten.Also haben wir das Projekt erstellt. Jetzt müssen wir nur noch etwas Code schreiben und ihn zum Laufen bringen :) Das Wichtigste zuerst: Wenn wir eine Anwendung erstellen wollen, die mit einer Datenbank funktioniert, kommen wir definitiv nicht ohne eine Datenbank aus! Laden Sie PostgreSQL hier herunter (ich verwende Version 9). PostgreSQL hat den Standardbenutzer „postgres“ – Sie müssen sich bei der Installation ein Passwort dafür ausdenken. Vergessen Sie das Passwort nicht. Wir werden es später brauchen! (Im Allgemeinen ist die Verwendung der Standarddatenbank in Anwendungen eine schlechte Praxis, aber wir werden dies tun, um die Anzahl der verursachten Geschwüre zu reduzieren, indem wir eine eigene Datenbank erstellen.) Wenn Sie mit der Befehlszeile und SQL-Abfragen nicht vertraut sind, gibt es gute Nachrichten. IntelliJ IDEA bietet eine rundum passende Benutzeroberfläche für die Arbeit mit der Datenbank. (befindet sich im rechten Bereich von IDEA, auf der Registerkarte „Datenbank“). Um eine Verbindung herzustellen, klicken Sie auf „+“ und wählen Sie unsere Datenquelle (PostgeSQL) aus. Füllen Sie die Felder für Benutzer und Datenbank („postgres“ für beide) aus und geben Sie das Passwort ein, das bei der Installation von PostgreSQL festgelegt wurde. Laden Sie bei Bedarf den Postgres-Treiber herunter. Sie können dies auf derselben Seite tun. Klicken Sie auf „Verbindung testen“, um zu überprüfen, ob die Datenbankverbindung hergestellt ist. Wenn Sie „Erfolgreich“ sehen, fahren Sie fort. Jetzt erstellen wir die Tabellen, die wir brauchen. Es wird insgesamt zwei geben: Benutzer und Autos. Parameter für die Benutzertabelle: Beachten Sie, dass id der Primärschlüssel ist. Wenn Sie den Primärschlüssel in SQL nicht kennen, googeln Sie ihn. Das ist wichtig. Einstellungen für die Autos-Tabelle: Für die Autos-Tabelle müssen Sie einen Fremdschlüssel konfigurieren. Es dient der Verknüpfung unserer Tabellen. Ich empfehle Ihnen, mehr darüber zu lesen. Vereinfacht ausgedrückt verweist es auf eine externe Tabelle, in unserem Fall auf Benutzer. Wenn ein Auto dem Benutzer mit der ID = 1 gehört, ist das Feld „user_id“ der Autos gleich 1. Auf diese Weise verknüpfen wir Benutzer in unserer Anwendung mit ihren Autos. In unserer Autos-Tabelle fungiert das Feld user_id als Fremdschlüssel. Es bezieht sich auf das ID-Feld der Benutzertabelle. Also haben wir eine Datenbank mit zwei Tabellen erstellt. Was bleibt, ist zu verstehen, wie man es über Java-Code verwaltet. Wir beginnen mit der Datei pom.xml, in die wir die erforderlichen Bibliotheken einbinden müssen (in Maven werden sie Abhängigkeiten genannt). Alle Bibliotheken werden im zentralen Maven-Repository gespeichert. Die von Ihnen in pom.xml angegebenen Bibliotheken stehen Ihnen zur Verwendung im Projekt zur Verfügung. Ihre pom.xml sollte so aussehen: Nichts Kompliziertes, wie Sie sehen können. Wir haben nur zwei Abhängigkeiten hinzugefügt – für die Verwendung von PostgreSQL und Hibernate. Kommen wir nun zum Java-Code. Erstellen Sie alle erforderlichen Pakete und Klassen im Projekt. Zunächst benötigen wir ein Datenmodell: die User
und- Auto
Klassen.
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;
}
}
Wie Sie sehen, enthalten Klassen eine Reihe undurchsichtiger Anmerkungen. Fangen wir an, uns mit ihnen auseinanderzusetzen. Für uns ist die Hauptannotation @Entity. Lesen Sie darüber auf Wikipedia und lernen Sie alles auswendig. Dies ist das Fundament der Stiftung. Mit dieser Annotation können Objekte Ihrer Java-Klasse einer Datenbank zugeordnet werden. Damit eine Klasse eine Entität ist, muss sie die folgenden Anforderungen erfüllen:
- Es muss einen leeren Konstruktor (
public
oderprotected
) haben. - Es kann nicht verschachtelt werden, eine Schnittstelle oder ein
enum
- Es kann und darf keine Felder/Eigenschaften
final
habenfinal
- Es muss mindestens ein @Id-Feld enthalten.
- Es kann nicht leere Konstruktoren haben
- Es kann erben und vererbt werden
- Es kann andere Methoden haben und Schnittstellen implementieren.
User
ist die Klasse der Benutzertabelle sehr ähnlich. Es hat id
, name
undage
Felder. Die darüber befindlichen Anmerkungen bedürfen keiner besonderen Erklärung: Es ist klar, dass @Id angibt, dass das Feld ein Bezeichner von Objekten dieser Klasse ist. Die Annotation @Table über der Klasse gibt den Namen der Tabelle an, in die die Objekte geschrieben werden. Beachten Sie den Kommentar über dem Altersfeld: Wenn der Name des Felds in der Klasse mit dem Namen der Tabelle übereinstimmt, können Sie die Annotation @Column weglassen und es wird funktionieren. Was den in den geschweiften Klammern angegebenen Teil betrifft („strategy = GenerationType.IDENTITY“): Es gibt mehrere Strategien zur Generierung von IDs. Sie können sie googeln, aber für unsere Anwendung brauchen Sie sich nicht die Mühe zu machen. Die Hauptsache ist, dass für unsere Objekte der Wert von id automatisch generiert wird. Dementsprechend gibt es keinen Setter für id und wir setzen ihn auch nicht im Konstruktor. Jedoch,User
Klasse sticht hervor. Es gibt eine Liste von Autos! Die Annotation @OneToMany hängt über der Liste. Dies bedeutet, dass mehrere Autos demselben Objekt der Benutzerklasse entsprechen können. Das Element „mappedBy“ verweist auf das Benutzerfeld der Auto
Klasse. Somit sind Autos und Benutzer miteinander verbunden. Das orphanRemoval-Element gibt an, ob der Entfernungsvorgang auf Entitäten angewendet werden soll, die keine Beziehung mehr haben. Wenn wir einen Benutzer aus der Datenbank löschen, werden auch alle damit verbundenen Autos gelöscht. Im Gegenzug in derAuto
Klasse sehen Sie das Benutzerfeld mit der Annotation @ManyToOne (ein Benutzer kann vielen Autos entsprechen) und der Annotation @JoinColumn. Es gibt an, welche Spalte in der Autos-Tabelle als Referenz auf die Benutzertabelle verwendet wird (dh der Fremdschlüssel, über den wir zuvor gesprochen haben). Nachdem Sie das Datenmodell erstellt haben, ist es an der Zeit, unserem Programm beizubringen, Operationen mit den Daten in der Datenbank durchzuführen. Beginnen wir mit der Dienstprogrammklasse HibernateSessionFactoryUtil. Es hat nur eine Aufgabe – eine Sitzungsfabrik zu erstellen, damit unsere Anwendung mit der Datenbank arbeiten kann (begrüßen Sie das Factory-Entwurfsmuster!). Es weiß nicht, wie es etwas anderes machen soll.
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 dieser Klasse erstellen wir ein neues Konfigurationsobjekt und übergeben ihm die Klassen, die es als Entitäten behandeln soll: User
und Auto
. Achten Sie auf die configuration.getProperties()
Methode. Welche weiteren Eigenschaften gibt es? Woher kommen sie? Eigenschaften sind die Ruhezustandseinstellungen, die in der speziellen Datei hibernate.cfg.xml angegeben sind. Hibernate.cfg.xml ist hier zu lesen: new Configuration().configure();
Wie Sie sehen, ist daran nichts Besonderes: Es enthält die Parameter für die Verbindung zur Datenbank sowie den Parameter show_sql. Dies ist erforderlich, damit alle von Hibernate ausgeführten SQL-Abfragen auf der Konsole angezeigt werden. Auf diese Weise können Sie genau sehen, was Hibernate zu einem bestimmten Zeitpunkt tut, und jegliches Gefühl von „Magie“ eliminieren. Als nächstes brauchen wir dasUserDAO
Klasse. Die beste Vorgehensweise besteht darin, über die Schnittstellen zu programmieren – erstellen Sie eine separate UserDAO
Schnittstelle und UserDAOImpl
Implementierung, aber ich werde dies überspringen, um die Codemenge zu reduzieren. Tun Sie dies nicht in echten Projekten! Das DAO-Entwurfsmuster (Data Access Object) ist eines der gebräuchlichsten. Die Idee ist einfach: Erstellen Sie eine Anwendungsschicht, die nur für den Zugriff auf Daten verantwortlich ist, nichts weiter. Daten aus der Datenbank abrufen, Daten aktualisieren, Daten löschen – fertig. Erfahren Sie mehr über DAO. Sie werden bei Ihrer Arbeit ständig Datenzugriffsobjekte verwenden. Was kann unsere UserDao
Klasse tun? Nun, wie alle DAOs kann es nur mit Daten arbeiten. Suchen Sie einen Benutzer anhand seiner ID, aktualisieren Sie seine Daten, löschen Sie ihn, rufen Sie eine Liste aller Benutzer aus der Datenbank ab oder speichern Sie einen neuen Benutzer in der Datenbank – das ist die Gesamtheit seiner Funktionen.
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
Die Methoden sind einander ähnlich. In den meisten Fällen erhalten wir mithilfe unserer Session Factory ein Sitzungsobjekt (Datenbankverbindungssitzung), erstellen eine einzelne Transaktion innerhalb dieser Sitzung, führen die erforderlichen Datenmanipulationen durch, speichern das Ergebnis der Transaktion in der Datenbank und schließen dann die Sitzung. Die Methoden selbst sind, wie Sie sehen, recht einfach. DAO ist das „Herz“ unserer Anwendung. Wir werden jedoch kein DAO direkt erstellen und seine Methoden in unserer main()
Methode aufrufen. Die gesamte Logik wird in die UserService
Klasse verschoben.
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);
}
}
Ein Dienst ist eine Anwendungsdatenschicht, die für die Ausführung der Geschäftslogik verantwortlich ist. Wenn Ihr Programm eine Geschäftslogik ausführen muss, erfolgt dies über Dienste. Ein Dienst enthält eine UserDao
und ruft in seinen Methoden DAO-Methoden auf. Es mag den Anschein haben, als würden wir hier Funktionen duplizieren (warum rufen wir die Methoden nicht einfach von einem DAO-Objekt aus auf?), aber bei vielen Objekten und komplexer Logik bietet die Schichtung der Anwendung enorme Vorteile (dies ist eine gute Vorgehensweise – denken Sie in Zukunft daran). und lesen Sie mehr über „Anwendungsschichten“). Unser Dienst verfügt über eine einfache Logik, aber Dienstmethoden in realen Projekten enthalten viel mehr als eine Codezeile :) Jetzt haben wir alles, was Sie zum Ausführen der Anwendung benötigen! In der main()
Methode erstellen wir einen Benutzer und sein Auto, verknüpfen sie miteinander und speichern sie in der Datenbank.
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);
}
}
Wie Sie sehen können, verfügt die Benutzertabelle über einen eigenen Datensatz und die Autos-Tabelle über einen eigenen Datensatz. Versuchen wir, unseren Benutzer umzubenennen. Löschen Sie die Benutzertabelle und führen Sie den Code aus
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);
}
}
Es klappt! Was passiert, wenn Sie den Benutzer löschen? Löschen Sie die Benutzertabelle (autos löscht sich selbst) und führen Sie den Code aus
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);
}
}
Und unsere Tabellen sind komplett leer (achten Sie auf die Konsole – dort werden alle von Hibernate ausgeführten Anfragen angezeigt). Sie können mit der Anwendung herumspielen und alle Funktionen ausprobieren. Erstellen Sie beispielsweise einen Benutzer mit Autos, speichern Sie ihn in der Datenbank, sehen Sie sich die dem Benutzer zugewiesene ID an und versuchen Sie, diese ID im zu verwendenmain()
Methode, um den Benutzer aus der Datenbank abzurufen und eine Liste seiner Autos auf der Konsole anzuzeigen. Natürlich haben wir nur einen kleinen Teil der Funktionalität von Hibernate gesehen. Seine Fähigkeiten sind sehr breit gefächert und es ist seit langem ein Standard-Branchentool für die Java-Entwicklung. Wer sich ausführlich damit beschäftigen möchte, dem kann ich das Buch „Java Persistence API and Hibernate“ empfehlen. Ich habe es in einem früheren Artikel rezensiert. Ich hoffe, dieser Artikel war für die Leser hilfreich. Wenn Sie Fragen haben, stellen Sie diese in den Kommentaren. Ich antworte gerne :) Vergessen Sie auch nicht, den Autor beim Wettbewerb zu unterstützen, indem Sie ein „Gefällt mir“ posten. Oder noch besser: „Ich liebe es“ :) Viel Glück beim Lernen!
GO TO FULL VERSION