Objektzustände in der Sitzung des Ruhezustands

1. Einleitung

Der Ruhezustand ist ein praktisches Framework für die Verwaltung persistenter Daten, aber es kann manchmal schwierig sein, zu verstehen, wie es intern funktioniert.

In diesem Tutorial erfahren Sie mehr über Objektzustände und wie Sie zwischen ihnen wechseln können. Wir werden uns auch die Probleme ansehen, die bei getrennten Entitäten auftreten können, und wie man sie löst.

2. Sitzung des Ruhezustands

Die Sitzungsschnittstelle ist das Hauptwerkzeug für die Kommunikation mit dem Ruhezustand. Es bietet eine API, mit der wir persistente Objekte erstellen, lesen, aktualisieren und löschen können. Die Sitzung hat einen einfachen Lebenszyklus. Wir öffnen es, führen einige Operationen durch und schließen es dann.

Wenn wir die Objekte während der Sitzung bearbeiten , werden sie an diese Sitzung angehängt . Die von uns vorgenommenen Änderungen werden beim Schließen erkannt und gespeichert. Nach dem Schließen unterbricht der Ruhezustand die Verbindungen zwischen den Objekten und der Sitzung.

3. Objektzustände

Im Kontext der Sitzung im Ruhezustand können sich Objekte in einem von drei möglichen Zuständen befinden: vorübergehend, dauerhaft oder getrennt.

3.1. Vorübergehend

Ein Objekt, das wir keiner Sitzung zugeordnet haben, befindet sich im Übergangszustand. Da es nie beibehalten wurde, hat es keine Darstellung in der Datenbank. Da keine Sitzung davon Kenntnis hat, wird es nicht automatisch gespeichert.

Lassen Sie uns mit dem Konstruktor ein Benutzerobjekt erstellen und bestätigen, dass es nicht von der Sitzung verwaltet wird:

Session session = openSession(); UserEntity userEntity = new UserEntity("John"); assertThat(session.contains(userEntity)).isFalse();

3.2. Hartnäckig

Ein Objekt, das wir einer Sitzung zugeordnet haben, befindet sich im dauerhaften Zustand. Wir haben es entweder gespeichert oder aus einem Persistenzkontext gelesen, sodass es eine Zeile in der Datenbank darstellt.

Lassen Sie uns ein Objekt erstellen und dann die persist- Methode verwenden, um es persistent zu machen:

Session session = openSession(); UserEntity userEntity = new UserEntity("John"); session.persist(userEntity); assertThat(session.contains(userEntity)).isTrue();

Alternativ können wir die Speichermethode verwenden. Der Unterschied besteht darin, dass die persist- Methode nur ein Objekt speichert und die save- Methode bei Bedarf zusätzlich ihre Kennung generiert.

3.3. Löste sich

Wenn wir die Sitzung schließen , werden alle darin enthaltenen Objekte getrennt. Obwohl sie immer noch Zeilen in der Datenbank darstellen, werden sie von keiner Sitzung mehr verwaltet :

session.persist(userEntity); session.close(); assertThat(session.isOpen()).isFalse(); assertThatThrownBy(() -> session.contains(userEntity));

Als Nächstes lernen wir, wie vorübergehende und getrennte Entitäten gespeichert werden.

4. Speichern und erneutes Anhängen einer Entität

4.1. Speichern einer vorübergehenden Entität

Erstellen wir eine neue Entität und speichern sie in der Datenbank. Wenn wir das Objekt zum ersten Mal konstruieren, befindet es sich im Übergangszustand.

Um beharren unsere neue Einheit, werden wir die Verwendung bestehen Methode:

UserEntity userEntity = new UserEntity("John"); session.persist(userEntity);

Jetzt erstellen wir ein weiteres Objekt mit derselben Kennung wie das erste. Dieses zweite Objekt ist vorübergehend, da es noch von keiner Sitzung verwaltet wird , aber wir können es mit der persist- Methode nicht persistent machen . Es ist bereits in der Datenbank vertreten, daher ist es im Kontext der Persistenzschicht nicht wirklich neu.

Stattdessen verwenden wir die Zusammenführungsmethode , um die Datenbank zu aktualisieren und das Objekt dauerhaft zu machen :

UserEntity onceAgainJohn = new UserEntity("John"); session.merge(onceAgainJohn);

4.2. Speichern einer getrennten Entität

Wenn wir die vorherige Sitzung schließen , befinden sich unsere Objekte in einem getrennten Zustand. Ähnlich wie im vorherigen Beispiel sind sie in der Datenbank dargestellt, werden jedoch derzeit von keiner Sitzung verwaltet . Wir können sie mit der Zusammenführungsmethode wieder dauerhaft machen :

UserEntity userEntity = new UserEntity("John"); session.persist(userEntity); session.close(); session.merge(userEntity);

5. Verschachtelte Entitäten

Komplizierter wird es, wenn wir verschachtelte Entitäten betrachten. Angenommen, unsere Benutzerentität speichert auch Informationen zu seinem Manager:

public class UserEntity { @Id private String name; @ManyToOne private UserEntity manager; }

Wenn wir diese Entität speichern, müssen wir nicht nur über den Status der Entität selbst nachdenken, sondern auch über den Status der verschachtelten Entität. Lassen Sie uns eine persistente Benutzerentität erstellen und dann ihren Manager festlegen:

UserEntity userEntity = new UserEntity("John"); session.persist(userEntity); UserEntity manager = new UserEntity("Adam"); userEntity.setManager(manager);

Wenn wir versuchen, es jetzt zu aktualisieren, erhalten wir eine Ausnahme:

assertThatThrownBy(() -> { session.saveOrUpdate(userEntity); transaction.commit(); });
java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.baeldung.states.UserEntity.manager -> com.baeldung.states.UserEntity 

Dies geschieht, weil der Ruhezustand nicht weiß, was mit der vorübergehend verschachtelten Entität zu tun ist.

5.1. Bestehende verschachtelte Entitäten

Eine Möglichkeit, dieses Problem zu lösen, besteht darin, verschachtelte Entitäten explizit beizubehalten:

UserEntity manager = new UserEntity("Adam"); session.persist(manager); userEntity.setManager(manager);

Nach dem Festschreiben der Transaktion können wir dann die korrekt gespeicherte Entität abrufen:

transaction.commit(); session.close(); Session otherSession = openSession(); UserEntity savedUser = otherSession.get(UserEntity.class, "John"); assertThat(savedUser.getManager().getName()).isEqualTo("Adam");

5.2. Kaskadierende Operationen

Vorübergehende verschachtelte Entitäten können automatisch beibehalten werden, wenn die Kaskadeneigenschaft der Beziehung in der Entitätsklasse korrekt konfiguriert wird :

@ManyToOne(cascade = CascadeType.PERSIST) private UserEntity manager;

Wenn wir das Objekt beibehalten, wird diese Operation auf alle verschachtelten Entitäten kaskadiert:

UserEntityWithCascade userEntity = new UserEntityWithCascade("John"); session.persist(userEntity); UserEntityWithCascade manager = new UserEntityWithCascade("Adam"); userEntity.setManager(manager); // add transient manager to persistent user session.saveOrUpdate(userEntity); transaction.commit(); session.close(); Session otherSession = openSession(); UserEntityWithCascade savedUser = otherSession.get(UserEntityWithCascade.class, "John"); assertThat(savedUser.getManager().getName()).isEqualTo("Adam");

6. Zusammenfassung

In diesem Tutorial haben wir einen genaueren Blick auf , wie die Hibernate Session arbeitet in Bezug auf Objektzustand. Wir haben dann einige Probleme untersucht, die dadurch entstehen können, und wie man sie löst.

Wie immer ist der Quellcode über GitHub verfügbar.