In diesem Artikel lernen Sie eines der beliebtesten Enterprise-Frameworks für Java kennen und erstellen Ihre erste Anwendung mit Hibernate. Noch nie von Hibernate gehört? Vielleicht haben Sie davon gehört, es aber noch nicht genutzt? Oder versucht zu starten, aber es ist nicht gelungen? In allen drei Fällen willkommen zum 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:
Kommen wir nun zum Java-Code. Erstellen Sie alle notwendigen Pakete und Klassen für das Projekt. Zunächst benötigen wir Datenmodelle – Klassen
- Intellij Idea Ultimate Edition;
Laden Sie es von der offiziellen Website herunter und aktivieren Sie die 30-Tage-Testversion. - PostgeSQL ist eines der beliebtesten modernen Datenbankverwaltungssysteme (DBMS);
- Maven (bereits in IDEA integriert);
- Ein bisschen Geduld.
Was ist Ruhezustand?
Dies ist eine der beliebtesten Implementierungen des ORM-Modells. Das objektrelationale Modell beschreibt die Beziehungen zwischen Softwareobjekten und Datensätzen in der Datenbank. Natürlich ist die Funktionalität von Hibernate sehr umfangreich, wir konzentrieren uns jedoch auf die einfachsten Funktionen. Unser Ziel: eine CRUD-Anwendung (Erstellen, Lesen, Aktualisieren, Löschen) zu erstellen, die in der Lage ist:- 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 auch aus der Datenbank.
- Weisen Sie Benutzern Fahrzeugobjekte (Auto) zu. Erstellen, bearbeiten, finden und löschen Sie Autos aus der Datenbank.
- Darüber hinaus soll die Anwendung „verwaiste“ Autos automatisch aus der Datenbank entfernen. Diese. Wenn ein Benutzer gelöscht wird, müssen auch alle ihm gehörenden Autos aus der Datenbank gelöscht werden.
com.вашНикнейм.javarush
, dies hat keinerlei Auswirkungen auf den Betrieb der Anwendung. Wählen Sie als Artefakt-ID einen beliebigen Projektnamen aus. Sie können die Version auch unverändert lassen. Bestätigen Sie auf dem letzten Bildschirm einfach Ihre zuvor eingegebenen Daten. Also, wir haben das Projekt erstellt, jetzt müssen wir nur noch den Code schreiben und ihn zum Laufen bringen :) Zunächst einmal: Wenn wir eine Anwendung erstellen möchten, die mit einer Datenbank funktioniert, können wir auf keinen Fall auf eine Datenbank verzichten! Laden Sie PostgreSQL hier herunter (ich verwende Version 9). PostgreSQL hat den Standardbenutzer „postgres“, Sie müssen während der Installation ein Passwort dafür erstellen. Vergessen Sie Ihr Passwort nicht, wir brauchen es später! (Im Allgemeinen ist die Verwendung der Standarddatenbank in Anwendungen eine schlechte Praxis, aber um die Anzahl der Hämorrhoiden zu reduzieren, begnügen wir uns mit der Erstellung unserer eigenen Datenbank.) Wenn Sie mit der Befehlszeile und SQL-Abfragen nicht vertraut sind, gibt es gute Nachrichten. Intellij IDEA bietet eine durchaus geeignete Benutzeroberfläche für die Arbeit mit der Datenbank. Es sieht so aus: (befindet sich in der rechten Seitenleiste von IDEA, Registerkarte „Datenbank“) Um eine Verbindung herzustellen, klicken Sie auf „+“ und wählen Sie unseren Anbieter (PostgeSQL) aus. Füllen Sie die Felder mit dem Benutzer und dem Datenbanknamen (beide sind Postgres) aus und geben Sie das Passwort ein, das Sie bei der Installation von PostgreSQL festgelegt haben. Laden Sie bei Bedarf den Postgres-Treiber herunter. Dies kann auf derselben Seite erfolgen. Klicken Sie auf „Verbindung testen“, um zu überprüfen, ob die Verbindung zur Datenbank hergestellt ist. Wenn Sie die Aufschrift „Erfolgreich“ sehen, machen wir weiter. Jetzt erstellen wir die Tabellen, die wir brauchen. Es wird zwei davon geben – Benutzer und Autos. Parameter für die Benutzertabelle: Bitte beachten Sie, dass id der Primärschlüssel ist. Wenn Sie nicht wissen, was ein Primärschlüssel in SQL ist, googeln Sie ihn, er ist wichtig. Einstellung für die Autos-Tabelle: Für Autos müssen Sie den Fremdschlüssel konfigurieren – Fremdschlüssel. Es wird unsere Tabellen verknüpfen. Ich rate Ihnen, mehr über ihn zu lesen; Vereinfacht ausgedrückt bezieht es sich auf eine externe Tabelle, in unserem Fall auf Benutzer. Wenn das Auto einem Benutzer mit der ID=1 gehört, steht im Feld „user_id“ der Tabelle „autos“ der Wert 1. Auf diese Weise verbinden wir Benutzer in unserer Anwendung mit ihren Autos. In unserer Autos-Tabelle dient das Feld user_id als Fremdschlüssel. Es bezieht sich auf das ID-Feld der Benutzertabelle. Somit haben wir eine Datenbank mit zwei Tabellen erstellt. Es bleibt 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 der Maven-Sprache werden sie Abhängigkeiten genannt). Alle Bibliotheken werden im zentralen Maven-Repository gespeichert. Diejenigen davon, die Sie in pom.xml angeben, können Sie im Projekt verwenden. 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.
User
und 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;
//Sie können den Spaltennamen nicht angeben, wenn er mit dem Namen der Spalte in der Tabelle übereinstimmt
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;
//Sie können den Spaltennamen nicht angeben, wenn er mit dem Namen der Spalte in der Tabelle übereinstimmt
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, sind die Klassen mit einer Menge noch unklarer Anmerkungen ausgestattet. Beginnen wir mit der Auseinandersetzung mit ihnen. Die Hauptanmerkung für uns ist @Entity. Lesen Sie darüber auf Wikipedia und merken Sie sich alles, das ist die Grundlage der Grundlagen. Diese Annotation ermöglicht die Verknüpfung von Java-Objekten Ihrer Klasse mit der Datenbank. Damit eine Klasse eine Entität ist, muss sie die folgenden Anforderungen erfüllen:
public
Muss einen leeren Konstruktor ( oderprotected
) haben ;- Kann nicht verschachtelt werden, Schnittstelle oder
enum
; - Kann nicht sein
final
und darffinal
-fields/properties nicht enthalten; - Muss mindestens ein @Id-Feld enthalten.
- Enthalten nicht leere Konstruktoren;
- Vererbt werden und vererbt werden;
- Enthalten Sie andere Methoden und implementieren Sie Schnittstellen.
User
ist die Klasse der Benutzertabelle sehr ähnlich. Es gibt Felder id
, name
, age
. Die darüber befindlichen Anmerkungen bedürfen keiner großen Erklärung: Es ist bereits klar, dass @Id ein Hinweis darauf ist, dass das Feld ein Bezeichner von Objekten dieser Klasse ist. Die @Table-Annotation über der Klasse gibt den Namen der Tabelle an, in die die Objekte geschrieben werden. Achten Sie auf den Kommentar über dem Altersfeld: Wenn der Feldname in der Klasse und der Tabelle identisch ist, müssen Sie die Annotation @Column nicht hinzufügen, es funktioniert so. Bezüglich der in Klammern angegebenen „strategy = GenerationType.IDENTITY“: Es gibt mehrere Strategien zur ID-Generierung. Sie können es googeln, aber im Rahmen unserer Bewerbung müssen Sie sich nicht darum kümmern. Die Hauptsache ist, dass IDs für unsere Objekte automatisch generiert werden, es gibt also keinen Setter für die ID und wir geben sie auch nicht im Konstruktor an. Dennoch sticht die Klasse in mancher User
Hinsicht heraus . Er hat eine Liste mit Autos! Die Annotation @OneToMany erscheint über der Liste. Das bedeutet, dass ein Objekt der Benutzerklasse mehreren Maschinen entsprechen kann. Die Einstellung „mappedBY“ verweist auf das Benutzerfeld der Klasse Auto
. Auf diese Weise werden Maschinen und Benutzer miteinander verbunden. Die orphanRemoval-Einstellung lässt sich ganz gut aus dem Englischen übersetzen: „Waisen entfernen“. Wenn wir einen Benutzer aus der Datenbank löschen, werden auch alle mit ihm verknüpften Autos gelöscht. In der Klasse wiederum Auto
sehen Sie das Benutzerfeld mit der Annotation @ManyToOne (viele Autos können einem Benutzer entsprechen) und der Annotation @JoinColumn. Es gibt an, über welche Spalte in der Autos-Tabelle die Verbindung mit der Benutzertabelle erfolgt (derselbe Fremdschlüssel, über den wir zuvor gesprochen haben). Nachdem Sie ein Datenmodell erstellt haben, ist es an der Zeit, unserem Programm beizubringen, Operationen an diesen 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 (Hallo, das „Factory!“-Muster). Er kann nichts anderes tun.
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("Ausnahme!" + e);
}
}
return sessionFactory;
}
}
In dieser Klasse erstellen wir ein neues Konfigurationsobjekt, Configuration, und übergeben ihm die Klassen, die es als Entitäten wahrnehmen soll – User
und Auto
. Achten Sie auf die Methode configuration.getProperties()
. Welche anderen Eigenschaften? Wo? Eigenschaften sind Parameter für die Funktionsweise des Ruhezustands, die in einer speziellen Datei hibernate.cfg.xml angegeben werden. Hibernate.cfg.xml wird hier gelesen: new Configuration().configure();
Wie Sie sehen, enthält es nichts Besonderes – Parameter für die Verbindung zur Datenbank und einen speziellen Parameter show_sql. Es wird benötigt, damit alle SQL-Abfragen, die im Ruhezustand für unsere Datenbank ausgeführt werden, an die Konsole ausgegeben werden. Auf diese Weise können Sie genau sehen, was Hibernate zu jedem Zeitpunkt tut, und den „magischen“ Effekt beseitigen. Als nächstes brauchen wir die Klasse UserDAO
. (Im positiven Sinne müssen Sie über Schnittstellen programmieren – eine Schnittstelle erstellen UserDAO
und separat implementieren UserDAOImpl
, aber um die Menge an Code zu reduzieren, werde ich dies weglassen. Tun Sie dies nicht in echten Projekten!). DAO (Data Access Object) ist eines der gebräuchlichsten Entwurfsmuster, „Data Access“. Die Bedeutung ist einfach: Erstellen einer Ebene in der Anwendung, die nur für den Zugriff auf Daten und nichts anderes verantwortlich ist. Daten aus der Datenbank abrufen, Daten aktualisieren, Daten löschen – und fertig. Lesen Sie mehr über DAOs; Sie werden sie bei Ihrer Arbeit ständig verwenden. Was kann unsere Klasse tun UserDao
? Eigentlich kann es, wie alle DAOs, 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 sind alle 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;
}
}
Die Methoden UserDao
ähneln einander. In den meisten Fällen erhalten wir mithilfe unserer Session Factory ein Sitzungsobjekt (eine Sitzung, die eine Verbindung zu unserer Datenbank herstellt), erstellen eine einzelne Transaktion innerhalb dieser Sitzung, führen die erforderlichen Datentransformationen durch, speichern das Transaktionsergebnis in der Datenbank und schließen die Sitzung. Die Methoden selbst sind, wie Sie sehen, recht einfach. Das DAO ist das „Herz“ unserer Anwendung. Allerdings werden wir das DAO nicht direkt erstellen und seine Methoden in unserem aufrufen main()
. Die gesamte Logik wird in die verschoben 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);
}
}
Der Dienst ist eine Datenschicht in der Anwendung, die für die Ausführung der Geschäftslogik verantwortlich ist. Wenn Ihr Programm Geschäftslogik ausführen muss, erledigt es dies über Dienste. Der Dienst enthält in sich selbst UserDao
und ruft in seinen Methoden DAO-Methoden auf. Für Sie mag das wie eine Duplizierung von Funktionen erscheinen (warum nicht einfach Methoden von einem Dao-Objekt aufrufen), aber bei einer großen Anzahl von Objekten und komplexer Logik hat die Aufteilung der Anwendung in Schichten enorme Vorteile (dies ist eine gute Vorgehensweise, denken Sie an diese Informationen). Sehen Sie sich die Zukunft an und lesen Sie mehr über „Anwendungsschichten“. In unserem Service ist die Logik einfach, aber in realen Projekten enthalten Servicemethoden viel mehr als eine Codezeile :) Jetzt haben wir alles, was wir brauchen, damit die Anwendung funktioniert! Erstellen wir main()
in der Methode einen Benutzer und Maschinen für ihn, verbinden 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("Masha",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, hat die Benutzertabelle einen eigenen Eintrag und die Autos-Tabelle einen eigenen. Versuchen wir, unseren Benutzer umzubenennen. Löschen wir die Benutzertabelle und führen 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("Masha",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("Sasha");
userService.updateUser(user);
}
}
Funktioniert! Was passiert, wenn Sie einen Benutzer löschen? Lassen Sie uns die Benutzertabelle löschen (autos löscht sich selbst) und den Code ausführen
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("Masha",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("Sasha");
userService.updateUser(user);
userService.deleteUser(user);
}
}
Und unsere Tabellen sind völlig leer (achten Sie auf die Konsole, dort werden alle Abfragen angezeigt, die Hibernate ausgeführt hat). Sie können mit der Anwendung herumspielen und alle Funktionen ausprobieren. Erstellen Sie beispielsweise einen Benutzer mit Maschinen, speichern Sie ihn in der Datenbank, sehen Sie, welche ID ihm zugewiesen ist, und versuchen Sie, main()
den Benutzer mithilfe der Methode anhand dieser ID aus der Datenbank zu „ziehen“ und eine Liste seiner Maschinen in der Konsole anzuzeigen . Natürlich haben wir nur einen kleinen Teil der Funktionalität von Hibernate gesehen. Seine Fähigkeiten sind sehr umfangreich und es ist seit langem einer der Industriestandards für die Java-Entwicklung. Wenn Sie es im Detail studieren möchten, kann ich das Buch „Java Persistence API and Hibernate“ empfehlen, das ich in einem meiner vorherigen Artikel rezensiert habe . Ich hoffe, dieser Artikel war für die Leser nützlich. Wenn Sie Fragen haben, stellen Sie diese in den Kommentaren, ich beantworte sie gerne :) Vergessen Sie auch nicht, den Autor im Wettbewerb zu unterstützen, indem Sie ihn mit „Gefällt mir“ markieren. Oder noch besser: „Es gefällt mir sehr gut“ :) Viel Erfolg im Studium!
GO TO FULL VERSION