Erste Schritte mit jOOQ

1. Einleitung

In diesem Tutorial werden wir einen kurzen Überblick über die Ausführung einer Anwendung mit jOOQ (Java Object Orientated Query) geben. Diese Bibliothek generiert Java-Klassen basierend auf den Datenbanktabellen und ermöglicht es uns, typsichere SQL-Abfragen über ihre fließende API zu erstellen.

Wir werden das gesamte Setup, die PostgreSQL-Datenbankverbindung und einige Beispiele für CRUD-Operationen behandeln.

2. Maven-Abhängigkeiten

Für die jOOQ-Bibliothek benötigen wir die folgenden drei jOOQ-Abhängigkeiten:

 org.jooq jooq 3.13.4   org.jooq jooq-meta 3.13.4   org.jooq jooq-codegen 3.13.4 

Wir benötigen außerdem eine Abhängigkeit für den PostgreSQL-Treiber:

 org.postgresql postgresql 42.2.16 

3. Datenbankstruktur

Bevor wir beginnen, erstellen wir ein einfaches DB-Schema für unsere Beispiele. Wir werden eine einfache Autoren- und eine Artikelbeziehung verwenden :

create table AUTHOR ( ID integer PRIMARY KEY, FIRST_NAME varchar(255), LAST_NAME varchar(255), AGE integer ); create table ARTICLE ( ID integer PRIMARY KEY, TITLE varchar(255) not null, DESCRIPTION varchar(255), AUTHOR_ID integer CONSTRAINT fk_author_id REFERENCES AUTHOR );

4. Datenbankverbindung

Schauen wir uns nun an, wie wir uns mit unserer Datenbank verbinden.

Zunächst müssen wir den Benutzer, das Kennwort und eine vollständige URL zur Datenbank angeben. Mit diesen Eigenschaften erstellen wir ein Verbindungsobjekt mithilfe des DriverManager und seiner Methode getConnection :

String userName = "user"; String password = "pass"; String url = "jdbc:postgresql://db_host:5432/baeldung"; Connection conn = DriverManager.getConnection(url, userName, password); 

Als nächstes müssen wir eine Instanz von DSLContext erstellen . Dieses Objekt wird unser Einstiegspunkt für jOOQ-Schnittstellen sein:

DSLContext context = DSL.using(conn, SQLDialect.POSTGRES);

In unserem Fall übergeben wir den POSTGRES- Dialekt, aber es gibt nur wenige andere wie H2, MySQL, SQLite und mehr.

5. Codegenerierung

Um Java-Klassen für unsere Datenbanktabellen zu generieren, benötigen wir die folgende Datei jooq-config.xml :

   org.postgresql.Driver jdbc:postgresql://db_url:5432/baeldung_database username password   org.jooq.codegen.JavaGenerator  org.jooq.meta.postgres.PostgresDatabase public .*    com.baeldung.jooq.model C:/projects/baeldung/tutorials/jooq-examples/src/main/java   

Die benutzerdefinierte Konfiguration erfordert Änderungen in der Abschnitt, in dem wir die Datenbankanmeldeinformationen und in der Abschnitt, in dem wir den Paketnamen und das Speicherortverzeichnis für die von uns generierten Klassen konfigurieren.

Um das Tool zur Generierung von jOOQ-Code auszuführen, müssen Sie den folgenden Code ausführen:

GenerationTool.generate( Files.readString( Path.of("jooq-config.xml") ) );

Nach Abschluss der Generierung erhalten wir die beiden folgenden Klassen, die jeweils der Datenbanktabelle entsprechen:

com.baeldung.model.generated.tables.Article; com.baeldung.model.generated.tables.Author;

6. CRUD- Operationen

Schauen wir uns nun einige grundlegende CRUD-Operationen an, die wir mit der jOOQ-Bibliothek ausführen können.

6.1. Erstellen

Lassen Sie uns zunächst einen neuen Artikeldatensatz erstellen . Dazu müssen wir die newRecord- Methode mit einer geeigneten Tabellenreferenz als Parameter aufrufen :

ArticleRecord article = context.newRecord(Article.ARTICLE);

Der Artikel.Artikelnummer Variable ist eine Referenz - Instanz auf die Artikel Datenbanktabelle. Es wurde automatisch von jOOQ während der Codegenerierung erstellt.

Als nächstes können wir Werte für alle benötigten Eigenschaften festlegen:

article.setId(2); article.setTitle("jOOQ examples"); article.setDescription("A few examples of jOOQ CRUD operations"); article.setAuthorId(1);

Schließlich müssen wir die Speichermethode für den Datensatz aufrufen , um sie in der Datenbank zu speichern:

article.store();

6.2. lesen

Nun wollen wir sehen, wie wir Werte aus der Datenbank lesen können. Als Beispiel wählen wir alle Autoren aus:

Result authors = context.select() .from(Author.AUTHOR) .fetch();

Hier verwenden wir die select- Methode in Kombination mit der from- Klausel, um anzugeben, aus welcher Tabelle wir lesen möchten. Durch Aufrufen der Abrufmethode wird die SQL-Abfrage ausgeführt und das generierte Ergebnis zurückgegeben.

The Result object implements the Iterable interface, so it's easy to iterate over each element. And while having access to a single record, we can get its parameters by using the getValue method with a proper field reference:

authors.forEach(author -> { Integer id = author.getValue(Author.AUTHOR.ID); String firstName = author.getValue(Author.AUTHOR.FIRST_NAME); String lastName = author.getValue(Author.AUTHOR.LAST_NAME); Integer age = author.getValue(Author.AUTHOR.AGE); System.out.printf("Author %s %s has id: %d and age: %d%n", firstName, lastName, id, age); });

We can limit the select query to a set of specific fields. Let's fetch only the article ids and titles:

Result
    
      articles = context.select(Article.ARTICLE.ID, Article.ARTICLE.TITLE) .from(Author.AUTHOR) .fetch();
    

We can also select a single object with the fetchOne method. The parameters for this one are the table reference and a condition to match the proper record.

In our case, let's just select an Author with an id equal to 1:

AuthorRecord author = context.fetchOne(Author.AUTHOR, Author.AUTHOR.ID.eq(1))

If no record matches the condition, the fetchOne method will return null.

6.3. Updating

To update a given record, we can use the update method from the DSLContext object combined with a set method invocations for every field we need to change. This statements should be followed by a where clause with a proper match condition:

context.update(Author.AUTHOR) .set(Author.AUTHOR.FIRST_NAME, "David") .set(Author.AUTHOR.LAST_NAME, "Brown") .where(Author.AUTHOR.ID.eq(1)) .execute();

The update query will run only after we call the execute method. As a return value, we'll get an integer equal to the number of records that were updated.

It's also possible to update an already fetched record by executing its store method:

ArticleRecord article = context.fetchOne(Article.ARTICLE, Article.ARTICLE.ID.eq(1)); article.setTitle("A New Article Title"); article.store();

The store method will return 1 if the operation was successful or 0 if the update was not necessary. For example, nothing was matched by the condition.

6.4. Deleting

To delete a given record, we can use the delete method from the DSLContext object. The delete condition should be passed as a parameter in the following where clause:

context.delete(Article.ARTICLE) .where(Article.ARTICLE.ID.eq(1)) .execute();

The delete query will run only after we call the execute method. As a return value, we'll get an integer equal to the number of deleted records.

It's also possible to delete an already fetched record by executing its delete method:

ArticleRecord articleRecord = context.fetchOne(Article.ARTICLE, Article.ARTICLE.ID.eq(1)); articleRecord.delete();

Die Löschmethode gibt 1 zurück, wenn der Vorgang erfolgreich war, oder 0, wenn das Löschen nicht erforderlich war. Zum Beispiel, wenn nichts von der Bedingung übereinstimmte.

7. Fazit

In diesem Artikel haben wir gelernt, wie Sie eine einfache CRUD-Anwendung mithilfe des jOOQ-Frameworks konfigurieren und erstellen. Wie üblich ist der gesamte Quellcode über GitHub verfügbar.