Ein Leitfaden zum OGM im Ruhezustand

1. Übersicht

In diesem Tutorial werden die Grundlagen von Hibernate Object / Grid Mapper (OGM) erläutert.

Hibernate OGM bietet Java Persistence API (JPA) -Unterstützung für NoSQL-Datenspeicher. NoSQL ist ein Überbegriff für eine Vielzahl von Datenspeichern. Dies umfasst beispielsweise Schlüsselwert-, Dokument-, spaltenorientierte und graphorientierte Datenspeicher.

2. Die Architektur von OGM im Ruhezustand

Hibernate bietet traditionell eine ORM-Engine (Object Relational Mapping) für relationale Datenbanken. Die OGM-Engine im Ruhezustand erweitert ihre Funktionalität, um NoSQL-Datenspeicher zu unterstützen. Der Hauptvorteil der Verwendung ist die Konsistenz der JPA-Schnittstelle über relationale und NoSQL-Datenspeicher hinweg.

Hibernate OGM kann aufgrund von zwei Schlüsselschnittstellen, DatastoreProvider und GridDialect , eine Abstraktion über eine Reihe von NoSQL-Datenspeichern bereitstellen . Daher wird jeder neue NoSQL-Datenspeicher, den er unterstützt, mit einer Implementierung dieser Schnittstellen geliefert.

Bis heute werden nicht alle NoSQL-Datenspeicher unterstützt, aber es kann mit vielen von ihnen wie Infinispan und Ehcache (Schlüsselwert), MongoDB und CouchDB (Dokument) und Neo4j (Grafik) zusammenarbeiten.

Es unterstützt auch Transaktionen vollständig und kann mit Standard-JTA-Anbietern zusammenarbeiten. Erstens kann dies über den Jakarta EE-Container ohne explizite Konfiguration bereitgestellt werden. Darüber hinaus können wir einen eigenständigen JTA-Transaktionsmanager wie Narayana in der Java SE-Umgebung verwenden.

3. Setup

In diesem Tutorial verwenden wir Maven, um die erforderlichen Abhängigkeiten für die Arbeit mit Hibernate OGM abzurufen. Wir werden auch MongoDB verwenden.

Lassen Sie uns zur Verdeutlichung sehen, wie Sie sie für das Lernprogramm einrichten.

3.1. Maven-Abhängigkeiten

Sehen wir uns die Abhängigkeiten an, die für die Arbeit mit Hibernate OGM und MongoDB erforderlich sind:

 org.hibernate.ogm hibernate-ogm-mongodb 5.4.0.Final   org.jboss.narayana.jta narayana-jta 5.9.2.Final 

Hier ziehen wir die erforderlichen Abhängigkeiten durch Maven:

  • OGM-Dialekt im Ruhezustand für MongoDB
  • Narayana Transaction Manager (tatsächlicher Anbieter der JTA)

3.2. Persistenz-Einheit

Wir müssen auch Datenspeicher Details definieren im Hibernate persistance.xml :

 org.hibernate.ogm.jpa.HibernateOgmPersistence      

Beachten Sie die Definitionen, die wir hier bereitgestellt haben:

  • Der Wert des Attributtransaktionstyps als "JTA" (dies impliziert, dass wir einen JTA-Entitätsmanager von der EntityManagerFactory benötigen).
  • der Anbieter, der HibernateOgmPersistence für Hibernate OGM ist
  • einige zusätzliche Details zur Datenbank (diese variieren normalerweise zwischen verschiedenen Datenquellen)

Die Konfiguration setzt voraus, dass MongoDB ausgeführt wird und standardmäßig verfügbar ist. Ist dies nicht der Fall, können wir bei Bedarf jederzeit Einzelheiten mitteilen. In einem unserer vorherigen Artikel wird auch die Einrichtung von MongoDB ausführlich behandelt.

4. Entitätsdefinition

Nachdem wir die Grundlagen durchgearbeitet haben, definieren wir einige Entitäten. Wenn wir zuvor mit Hibernate ORM oder JPA gearbeitet haben, hat dies nichts mehr hinzuzufügen . Dies ist die Grundvoraussetzung von Hibernate OGM. Es verspricht, dass wir mit verschiedenen NoSQL-Datenspeichern nur mit dem Wissen von JPA arbeiten können .

In diesem Tutorial definieren wir ein einfaches Objektmodell:

Es definiert Artikel- , Autoren- und Editor- Klassen zusammen mit ihren Beziehungen.

Definieren wir sie auch in Java:

@Entity public class Article { @Id @GeneratedValue(generator = "uuid") @GenericGenerator(name = "uuid", strategy = "uuid2") private String articleId; private String articleTitle; @ManyToOne private Author author; // constructors, getters and setters... }
@Entity public class Author { @Id @GeneratedValue(generator = "uuid") @GenericGenerator(name = "uuid", strategy = "uuid2") private String authorId; private String authorName; @ManyToOne private Editor editor; @OneToMany(mappedBy = "author", cascade = CascadeType.PERSIST) private Set authoredArticles = new HashSet(); // constructors, getters and setters... }
@Entity public class Editor { @Id @GeneratedValue(generator = "uuid") @GenericGenerator(name = "uuid", strategy = "uuid2") private String editorId; private String editorName; @OneToMany(mappedBy = "editor", cascade = CascadeType.PERSIST) private Set assignedAuthors = new HashSet(); // constructors, getters and setters... }

Wir haben jetzt Entitätsklassen definiert und sie mit JPA-Standardanmerkungen versehen:

  • @Entity , um sie als JPA-Entitäten einzurichten
  • @Id , um Primärschlüssel für die Entitäten mit UUIDs zu generieren
  • @OneToMany und @ManyToOne , um bidirektionale Beziehungen zwischen den Entitäten herzustellen

5. Operationen

Nachdem wir unsere Entitäten erstellt haben, wollen wir sehen, ob wir einige Operationen an ihnen ausführen können. In einem ersten Schritt müssen wir einige Testdaten generieren. Hier erstellen wir einen Editor , einige Autoren und einen Artikel. Wir werden auch ihre Beziehungen aufbauen.

Bevor wir eine Operation ausführen können, benötigen wir eine Instanz von EntityManagerFactory. Damit können wir EntityManager erstellen . Zusammen mit diesem müssen wir TransactionManager erstellen, um Transaktionsgrenzen zu behandeln.

Mal sehen, wie wir diese verwenden können, um die zuvor erstellten Entitäten beizubehalten und abzurufen:

private void persistTestData(EntityManagerFactory entityManagerFactory, Editor editor) throws Exception { TransactionManager transactionManager = com.arjuna.ats.jta.TransactionManager.transactionManager(); transactionManager.begin(); EntityManager entityManager = entityManagerFactory.createEntityManager(); entityManager.persist(editor); entityManager.close(); transactionManager.commit(); }

Hier verwenden wir EntityManager, um die Stammentität beizubehalten, die zu allen ihren Beziehungen kaskadiert. Wir führen diese Operation auch innerhalb einer definierten Transaktionsgrenze durch.

Jetzt können wir die Entität laden, die wir gerade beibehalten haben, und ihren Inhalt überprüfen. Wir können einen Test durchführen, um dies zu überprüfen:

@Test public void givenMongoDB_WhenEntitiesCreated_thenCanBeRetrieved() throws Exception { EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("ogm-mongodb"); Editor editor = generateTestData(); persistTestData(entityManagerFactory, editor); TransactionManager transactionManager = com.arjuna.ats.jta.TransactionManager.transactionManager(); transactionManager.begin(); EntityManager entityManager = entityManagerFactory.createEntityManager(); Editor loadedEditor = entityManager.find(Editor.class, editor.getEditorId()); assertThat(loadedEditor).isNotNull(); // Other assertions to verify the entities and relations }

Hier verwenden wir den EntityManager erneut, um die Daten zu finden und Standardzusicherungen durchzuführen. Wenn wir diesen Test ausführen, wird der Datenspeicher instanziiert, die Entitäten bleiben erhalten, sie werden abgerufen und überprüft.

Wieder haben wir gerade JPA verwendet, um die Entitäten zusammen mit ihrer Beziehung beizubehalten . In ähnlicher Weise verwenden wir JPA, um die Entitäten zurück zu laden, und alles funktioniert einwandfrei, selbst wenn unsere Datenbankauswahl MongoDB anstelle einer herkömmlichen relationalen Datenbank ist.

6. Backend wechseln

Wir können auch unser Backend wechseln. Lassen Sie uns jetzt herausfinden, wie schwierig es sein wird, dies zu tun.

Wir werden unser Backend auf Neo4j ändern, einen beliebten graphorientierten Datenspeicher.

Fügen wir zunächst die Maven-Abhängigkeit für Neo4j hinzu:

 org.hibernate.ogm hibernate-ogm-neo4j 5.4.0.Final 

Als nächstes müssen wir die entsprechende Persistenz-Einheit in unsere persistence.xml einfügen :

 org.hibernate.ogm.jpa.HibernateOgmPersistence      

Kurz gesagt, dies sind die grundlegenden Konfigurationen, die für Neo4j erforderlich sind. Dies kann bei Bedarf näher erläutert werden.

Nun, das ist so ziemlich das, was getan werden muss. Wenn wir denselben Test mit Neo4j wie den Backend-Datenspeicher ausführen, funktioniert dies ziemlich nahtlos.

Beachten Sie, dass wir unser Backend von MongoDB, einem dokumentenorientierten Datenspeicher, auf Neo4j, einen graphorientierten Datenspeicher, umgestellt haben. Und das alles mit minimalen Änderungen und ohne Änderungen an unseren Abläufen .

7. Fazit

In diesem Artikel haben wir die Grundlagen von Hibernate OGM einschließlich seiner Architektur durchgearbeitet. Anschließend haben wir ein grundlegendes Domänenmodell implementiert und verschiedene Operationen mit verschiedenen DBs durchgeführt.

Wie immer ist der Code für die Beispiele auf GitHub verfügbar.