jOOQ??? jOOQ!!
jOOQ (Java Object Oriented Querying) ist ein Framework, das es ermöglicht, SQL-Abfragen in Java-Code zu schreiben. Und zwar auf eine Art und Weise, die sowohl typisiert als auch gut lesbar ist. Im Gegensatz zu reinen ORM-Frameworks, wie z.B. Hibernate, bleibt jOOQ eng am zugrunde liegenden relationalen Datenbank-Modell und nutzt dessen volle Leistungsfähigkeit.
Im Folgenden schauen wir uns ein einfaches Beispiel an, welches dir die Konzepte von jOOQ näher bringt und dir einen ersten Eindruck von jOOQ vermittelt. Als Grundlage verwenden wir eine Spring Boot Applikation, deren Source Code du in unserem GitLab finden kannst.
Einführung in JOOQ
Bevor du mit jOOQ arbeiten kannst, definierst du die benötigten Abhängigkeiten, zum Beispiel im pom.xml für Maven:
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq</artifactId>
<version>3.19.9</version>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq-meta</artifactId>
<version>3.19.9</version>
</dependency>
<dependency>
<groupId>org.jooq</groupId>
<artifactId>jooq-codegen</artifactId>
<version>3.19.9</version>
</dependency>
Oder mit gradle:
implementation "org.jooq:jooq:3.19.9" implementation "org.jooq:jooq-meta:3.19.9" implementation "org.jooq:jooq-codegen:3.19.9"
Als ersten Schritt definierst du das Datenbankmodell, da jOOQ den Ansatz «Database First» verfolgt. Das bedeutet, du schenkst der Entwicklung des Datenbankmodells wieder mehr Aufmerksamkeit, und es ist nicht länger nur ein Nebenprodukt von ORM-Frameworks. Darüber freuen sich insbesondere DB-Designer und DB-Engineers. In unserer Beispiel-App verwenden wir das einfache scott/tiger-Schema, das Oracle vor vielen Jahren zu Demozwecken eingesetzt hat.
Im zweiten Schritt generierst du aus dem bestehenden Datenbankmodell die notwendigen Klassen, die du für den Datenbankzugriff benötigst. Mit diesen Klassen formulierst du anschliessend auf sehr angenehme Art und Weise deine Abfragen und DML-Statements.
Im pom.xml definierst und konfigurierst du den jOOQ-Generator. Dafür verwenden wir das Maven-Plugin testcontainers-jooq-codegen-maven-plugin. Du kannst dieses Plugin vor der Compile-Phase einsetzen, um die notwendigen Klassen für den Datenbankzugriff zu generieren.
<generate> <javaTimeTypes>true</javaTimeTypes> <pojos>true</pojos> <daos>true</daos> <fluentSetters>true</fluentSetters> <validationAnnotations>true</validationAnnotations> <springAnnotations>true</springAnnotations> </generate>
In unserem Beispiel verwenden wir einen Docker-Container für die Datenbank und führen die Migrationsskripte aus, damit wir den endgültigen Zustand des Datenbankmodells erhalten. Die oben aufgeführten Parameter ermöglichen es dir, die gewünschten Klassen wie DAOs und POJOs in der notwendigen Ausprägung zu generieren, zum Beispiel mit Fluent APIs, Validierungsannotationen oder Spring-Boot-Annotationen. In unserem Beispiel legen wir die generierten Klassen in einem separaten Bereich ab und speichern sie als Source Code, damit wir nachträgliche Änderungen am Datenbankmodell und damit auch an den generierten Klassen sofort erkennen.
jOOQ generiert pro Entität eine Klasse sowie einen Record, mit denen wir die Tabelle und deren Attribute abbilden. Falls wir möchten, generieren wir in unserem Beispiel zusätzlich DAOs und POJOs, wiederum jeweils eine Klasse pro Entität. Die DAOs stellen uns die typischen CRUD-Funktionen für jede Entität zur Verfügung und bieten zusätzlich eine Vielzahl von Fetch-Methoden.
Da SQL nicht nur CRUD umfasst, sondern deutlich mehr Möglichkeiten bietet, implementieren wir spezifische Repository-Klassen, wie sie in einer Spring-Boot-Applikation mit @Repository eingesetzt werden. Genau hier zeigt jOOQ seine eigentliche Stärke, denn wir implementieren komplexe SQL-Statements direkt in Java.
Im zweiten Beispiel (Klasse EmployeeRepositoryImpl) ist ein weiteres cooles Feature von jOOQ zu finden: Die Methoden create() und update() geben das vollständige, soeben gespeicherte Objekt zurück, so wie es aktuell auf der Datenbank vorliegt. Was typischerweise mit einem nachträglichen Select Statement abgefragt werden muss, kann jOOQ gleich in einem DB-Roundtrip erledigen, indem im Fluent-API die Methode returningResult() verwendet wird. Effektiv wird auf der DB das Select Statement ausgeführt und das Resultat evaluiert, aber eben ohne erneuten DB-Zugriff aus der Applikation.
Zudem bietet jOOQ die Metadaten des DB-Modells an (dsl.meta()). Anhand dieser Daten kann z.B. ein einfacher PlantUML-Generator geschrieben werden, um die DB-Dokumentation zu generieren, entweder auf Knopfdruck oder automatisch via Cron Job – damit ist auch das Thema «Dokumentation» erledigt! Auch dazu findest du ein Beispiel in unserer App (Klasse PlantUmlGenerator).
Fazit oder warum jOOQ?
Wir setzen jOOQ in unserem Projekt konsequent in der Backend-Entwicklung ein. Ausgehend vom Datenbank-Modell lassen wir die notwendigen Klassen generieren, um selber die Repository-Klassen pro Entität zu implementieren.
Die Vorteile gegenüber Hibernate liegen darin, dass der Ansatz «Database First» verfolgt wird und aus dem Datenbank-Modell die Klassen generiert werden. Zuerst muss sich der Entwickler mit der Modellierung der Datenbank-Objekte beschäftigen, bevor der DB-Zugriff und die Business Logik implementiert werden. Somit wird der Modellierung wieder mehr Aufmerksamkeit gewidmet und ist nicht mehr länger ein «Nebenprodukt» des OR-Mappings. Weitere Features und Vorteile:
- Typsicherheit: Der Compiler prüft bereits beim Schreiben des Codes, ob Spaltennamen, Tabellen und Datentypen korrekt sind. Tippfehler führen zu Kompilierfehlern statt zu Laufzeit-SQL-Fehlern.
- Fluent API: SQL wird als Java-Methodenkette ausgedrückt (DSL.select(…).from(…).where(…)). Das wirkt natürlich und lässt sich leicht lesen.
- Vollständige SQL-Abdeckung: Fast jede SQL-Funktion, jedes Dialekt-Feature (z.B. PostgreSQL, MySQL, Oracle u.a.) ist verfügbar. Man muss nicht auf ein vereinfachtes Subset zurückgreifen.
- Code-Generierung: jOOQ erzeugt Java-Klassen, die exakt den Tabellen, Views und Stored Procedures deines DB-Modells entsprechen.
- Integration: Lässt sich problemlos mit Spring, Micronaut oder anderen Frameworks kombinieren und unterstützt sowohl JDBC als auch R2DBC.
jOOQ ist gratis erhältlich (Open Source) für die gängigsten Datenbanken wie H2, MariaDB oder PostgreSQL. Weitere Editionen wie Express, Professional oder Enterprise unterstützen weitere DB-Dialekte und bieten zusätzliche Features und Support an.