Skip to content
Snippets Groups Projects
user avatar
Julian Horner authored
c93e9b61
History
Name Last commit Last update
src/main
.gitignore
README.md
pom.xml

NoSQL-Datenbank für My-Aktion

Worum geht es in diesem Projekt?

Die Aufgabe dieses Projekts ist es die relationale H2-Datenbank des Projekts my-aktion durch die NoSQL-Datenbank MongoDB zu ersetzen, sowie dem anpassen von my-aktion an die neue Datenbank.

Zur Umsetzung wurde das Mapping-Framework Hibernate OGM genutzt. Hibernate OGM mappt die Entities der Anwendung nicht wie Hibernate ORM, an eine relationale Datenbank sondern an eine NoSQL-Datenbank. Im Falle des Projekt also an die MongoDB-Datenbank.

Hibernate OGM ist dazu in der Lage JPQL-Queries zu übersetzen in die Sprache der jeweilig angebundenen Datenbank. Der Programmierer muss also die Abfragesprache der genutzten Datenbank nicht zwangsläufig kennen. Auch die von der Anwendung genutzten JPA-Annotationen wie zum Beispiel NotNull oder ManyToOne werden unterstützt, also müssen auch hier keine Anpassungen vorgenommen werden.

Aufgetretene Probleme

Aggregatfunktionen in Hibernate OGM

Da Hibernate OGM ein laufender Prozess ist können bislang nur manche Sprachkonstrukte von JPQL in andere Abfragesprachen übersetzt werden. Was genau übersetzt wird unterscheidet sich je nach genutzter Datenbank. Die Version für MongoDB-Datenbanken unterstützt die folgenden Konstrukte von JPQL:

  • einfache Vergleiche mit "<", "<=", "=", ">=" und ">"
  • IS NULL und IS NOT NULL
  • Die booleschen OperatorenAND, OR und NOT
  • LIKE, IN und BETWEEN
  • ORDER BY

Im Projekt my-aktion wird an einer Stelle die SQL-Aggregatfunktion SUM genutzt, in der Dokumentation werden diese nicht bei unterstützten Konstrukten aufgezählt, allerdings scheint denoch zumindest eine teilweiße Unterstützung für HQL zu bestehen. Näheres weiter unten. Die restlichen Queries konnten Problemlos weiter genutzt werden ohne spezielle Anpassungen vornehmen zu müssen.

Der unten dargestellte Code zeigt die Methode in welcher die Abfrage mit der Summenfunktion aufgerufen wird. Der einzige Unterschied zwischen diesem und den anderen Methoden in der Klasse ist der dass anstatt der JPA-API die Hibernate-Native-API genutzt wird und damit HQL anstatt JPQL.

@RolesAllowed("Organizer")
@Stateless
public class CampaignServiceBean implements CampaignService {    
    // ----------------------------------------------------------------------------------------------
    
    ...

    private Double getAmountDonatedSoFar(Campaign campaign) {        
	Session session = entityManager.unwrap(Session.class);

        Double result = session.createNamedQuery(Campaign.getAmountDonatedSoFar, Double.class)
                .setParameter("campaign", campaign).uniqueResult();
        if (result == null)
            result = 0d;

        return result;
    }
    
    ...

    // ----------------------------------------------------------------------------------------------
}

Da im Code nur auf das Session-Interface zugegriffen wird und nicht direkt auf die OgmSession, sollte die Methode auch mit einer Hibernate-ORM-Lösung lauffähig sein, müsste also nicht extra angepasst werden. Der Nachteil dieser Methode ist allerdings dass die reine Nutzung von JPA damit entfällt und somit nicht einfach auf einen andere Implementierung wie zum Beispiel EclipseLink umgestiegen werden könnte.

Die Lösung wurde auf der folgenden Webseite gefunden https://www.gregoriopalama.com/mongodb-on-wildfly-using-hibernate-ogm/

Nach weiterer Recherche warum das genannte funktioniert, obwohl gegenteiliges in der Dokumentation behauptet wird, konnten folgende JIRA-Einträge von Hibernate OGM gefunden werden.

Beide sind als erledigt markiert. Im ersten wird Support für die SQL-Aggregatfunktion Count hinzugefügt. Diese Änderung ist bereits veröffentlicht worden in der Version 5.4.1 (siehe zweiter Link) welche die aktuelle Veröffentlichung darstellt und die im Projekt genutzte.

Des Weiteren ist auf der ersten Seite die Aufgabe verlinkt die weiteren Aggregatfunktionen zu implementieren. Die verlinkte Aufgabe ist der dritte Link. Wenn man sich den Github Link für den dazugehörigen Pull Request ansieht und dessen Kommentare und Commits sieht es so aus als ob die Änderungen bereits veröffentlicht wurden die Dokumentation diesbezüglich aber nicht aktualisiert worden ist.

Eine Alternative wäre noch gewesen den NamedQuery mit der "criteria-only find syntax" oder der "MongoDB CLI syntax" zu schreiben. Da ein einfaches wechseln zwischen Hibernate ORM und OGM dadurch erschwert würden wurde bewusst darauf verzichtet.

Organizer-Dokument

Da die Dokumente in einer MongoDB-Datenbank immer einen eindeutigen Identifier im Feld _id haben müssen, wurde in die Organizer-Entity ein Feld Id eingefügt welches das email-Feld als Identifier ersetzt. Damit dennoch sichergestellt wird das eine bestimmte E-Mail nur einmal vorkommt in der Tabelle, wurde an das email-Feld die Annotation @Column(unique = true) angehängt (siehe untenstehender Code).

@Entity
public class Organizer extends DateEntity {
    //----------------------------------------------------------------------------------------------

    public static final String findByEmail = "Organizer.findByEmail";

    //==============================================================================================

    @GeneratedValue
    @Id
    private Long id;
    
    @NotNull
    @Size(min = 3, max = 20, message = "{organizer.firstName.size}")
    private String firstName;

    @NotNull
    @Size(min = 3, max = 30, message = "{organizer.lastName.size}")
    private String lastName;

    @Pattern(regexp = ".+@.+", message = "{organizer.email.pattern}")
    @Column(unique = true)
    private String email;

    @NotNull
    private String password;

    //----------------------------------------------------------------------------------------------
    
    ...
}

Wie startet man das Projekt?

Voraussetzungen

  • Eine MongoDB-Datenbank-Instanz muss auf dem Rechner laufen (unter default port und localhost).
  • Die Datenbank muss den Namen my-aktion haben.
  • Es muss eine Sammlung existieren in welchen die Benutzer der Applikation gespeichert werden.
  • Die Sammlung welche die Benutzer enthält muss den Namen Organizer tragen.

Ausführen

Das Projekt kann auf herkömmlich genutzte Weiße deployt werden also zum Beispiel mit dem Befehl

mvn clean package wildfly:deploy 

oder auch über die Benutzerschnittstelle von Wildfly die HAL-Management-Konsole.

Ansonsten sind keine besonderen Schritte zu tätigen.