Verwenden von Spring Data R2DBC mit Azure Database for PostgreSQL

In diesem Artikel wird die Erstellung einer Beispielanwendung veranschaulicht, die Spring Data R2DBC verwendet, um Informationen in einer Azure Database for PostgreSQL-Datenbank zu speichern bzw. daraus abzurufen. Im Beispiel wird die R2DBC-Implementierung für PostgreSQL aus dem r2dbc-postgresql-Repository auf GitHub verwendet.

R2DBC ermöglicht die Nutzung reaktiver APIs mit herkömmlichen relationalen Datenbanken. Sie können es zusammen mit Spring WebFlux verwenden, um vollständig reaktive Spring Boot-Anwendungen zu erstellen, die nicht blockierende APIs verwenden. Dies bietet bessere Skalierbarkeit als der klassische „Ein-Thread-pro-Verbindung“-Ansatz.

Voraussetzungen

Sehen Sie sich die Beispielanwendung an

In diesem Artikel codierten Sie eine Beispielanwendung. Wenn Sie schneller vorgehen möchten, ist diese Anwendung unter https://github.com/Azure-Samples/quickstart-spring-data-r2dbc-postgresql bereits programmiert und verfügbar.

Vorbereiten der Arbeitsumgebung

Richten Sie zunächst einige Umgebungsvariablen ein, indem Sie die folgenden Befehle ausführen:

export AZ_RESOURCE_GROUP=database-workshop
export AZ_DATABASE_SERVER_NAME=<YOUR_DATABASE_SERVER_NAME>
export AZ_DATABASE_NAME=<YOUR_DATABASE_NAME>
export AZ_LOCATION=<YOUR_AZURE_REGION>
export AZ_POSTGRESQL_ADMIN_USERNAME=spring
export AZ_POSTGRESQL_ADMIN_PASSWORD=<YOUR_POSTGRESQL_ADMIN_PASSWORD>
export AZ_POSTGRESQL_NON_ADMIN_USERNAME=nonspring
export AZ_POSTGRESQL_NON_ADMIN_PASSWORD=<YOUR_POSTGRESQL_NON_ADMIN_PASSWORD>
export AZ_LOCAL_IP_ADDRESS=<YOUR_LOCAL_IP_ADDRESS>

Ersetzen Sie die Platzhalter durch die folgenden Werte, die in diesem Artikel verwendet werden:

  • <YOUR_DATABASE_SERVER_NAME>: Der Name Ihres PostgreSQL-Servers, der in Azure eindeutig sein muss.
  • <YOUR_DATABASE_NAME>: Der Datenbankname Ihres PostgreSQL-Servers, der in Azure eindeutig sein muss.
  • <YOUR_AZURE_REGION>: Die von Ihnen verwendete Azure-Region. Sie können standardmäßig eastus verwenden, wir empfehlen aber, eine Region zu konfigurieren, die näher an Ihrem Standort liegt. Sie können die vollständige Liste der verfügbaren Regionen mithilfe az account list-locationsvon .
  • <YOUR_POSTGRESQL_ADMIN_PASSWORD> und <YOUR_POSTGRESQL_NON_ADMIN_PASSWORD>: Das Kennwort Ihres PostgreSQL-Datenbankservers, das mindestens acht Zeichen enthalten sollte. Es muss Zeichen aus drei der folgenden Kategorien enthalten: Englische Großbuchstaben, englische Kleinbuchstaben, Zahlen (0-9) und nicht alphanumerische Zeichen (!, $, #, % usw.).
  • <YOUR_LOCAL_IP_ADDRESS>: Die IP-Adresse Ihres lokalen Computers, auf dem Sie die Spring Boot-Anwendung ausführen. Sie können sie ganz einfach ermitteln, indem Sie whatismyip.akamai.com öffnen.

Erstellen Sie nun mithilfe des folgenden Befehls eine Ressourcengruppe:

az group create \
    --name $AZ_RESOURCE_GROUP \
    --location $AZ_LOCATION \
    --output tsv

Erstellen einer Azure-Datenbank für Die PostgreSQL-Instanz und Einrichten des Administratorbenutzers

Als Erstes erstellen Sie einen verwalteten PostgreSQL-Server mit einem Administratorbenutzer.

Hinweis

Ausführlichere Informationen zum Erstellen von PostgreSQL-Servern finden Sie unter Erstellen eines Azure Database for PostgreSQL-Servers im Azure-Portal.

az postgres flexible-server create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_DATABASE_SERVER_NAME \
    --location $AZ_LOCATION \
    --admin-user $AZ_POSTGRESQL_ADMIN_USERNAME \
    --admin-password $AZ_POSTGRESQL_ADMIN_PASSWORD \
    --yes \
    --output tsv

Konfigurieren einer PostgreSQL-Datenbank

Der von Ihnen zuvor erstellte PostgreSQL-Server ist leer. Erstellen Sie mit dem folgenden Befehl eine neue Datenbank:

az postgres flexible-server db create \
    --resource-group $AZ_RESOURCE_GROUP \
    --database-name $AZ_DATABASE_NAME \
    --server-name $AZ_DATABASE_SERVER_NAME \
    --output tsv

Konfigurieren einer Firewallregel für den PostgreSQL-Server

Azure Database for PostgreSQL-Instanzen sind standardmäßig gesichert. Sie besitzen eine Firewall, die keine eingehenden Verbindungen zulässt. Damit Sie die Datenbank verwenden können, müssen Sie eine Firewallregel hinzufügen, die den Zugriff der lokalen IP-Adresse auf den Datenbankserver zulässt.

Da Sie die lokale IP-Adresse zu Beginn dieses Artikels konfiguriert haben, können Sie die Firewall des Servers öffnen, indem Sie den folgenden Befehl ausführen:

az postgres flexible-server firewall-rule create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_DATABASE_SERVER_NAME \
    --rule-name $AZ_DATABASE_SERVER_NAME-database-allow-local-ip \
    --start-ip-address $AZ_LOCAL_IP_ADDRESS \
    --end-ip-address $AZ_LOCAL_IP_ADDRESS \
    --output tsv

Wenn Sie eine Verbindung mit Ihrem PostgreSQL-Server von Windows-Subsystem für Linux (WSL) auf einem Windows-Computer herstellen, müssen Sie der Firewall die WSL-Host-ID hinzufügen.

Rufen Sie die IP-Adresse Ihres Hostcomputers ab, indem Sie den folgenden Befehl in WSL ausführen:

cat /etc/resolv.conf

Kopieren Sie die IP-Adresse nach dem Ausdruck nameserver, und verwenden Sie dann den folgenden Befehl, um eine Umgebungsvariable für die WSL-IP-Adresse festzulegen:

export AZ_WSL_IP_ADDRESS=<the-copied-IP-address>

Verwenden Sie dann den folgenden Befehl, um die Firewall des Servers für Ihre WSL-basierte App zu öffnen:

az postgres flexible-server firewall-rule create \
    --resource-group $AZ_RESOURCE_GROUP \
    --name $AZ_DATABASE_SERVER_NAME \
    --rule-name $AZ_DATABASE_SERVER_NAME-database-allow-local-ip \
    --start-ip-address $AZ_WSL_IP_ADDRESS \
    --end-ip-address $AZ_WSL_IP_ADDRESS \
    --output tsv

Erstellen eines PostgreSQL-Nicht-Administratorbenutzers und Erteilen von Berechtigungen

Erstellen Sie nun einen Nicht-Administratorbenutzer, und gewähren Sie ihm alle Berechtigungen für die Datenbank.

Hinweis

Ausführlichere Informationen zum Erstellen von PostgreSQL-Benutzern finden Sie unter Erstellen von Benutzern in Azure Database for PostgreSQL.

Erstellen Sie ein SQL-Skript namens create_user.sql zum Erstellen eines Nicht-Administratorbenutzers. Fügen Sie den folgenden Inhalt hinzu, und speichern Sie das Skript lokal:

cat << EOF > create_user.sql
CREATE ROLE "$AZ_POSTGRESQL_NON_ADMIN_USERNAME" WITH LOGIN PASSWORD '$AZ_POSTGRESQL_NON_ADMIN_PASSWORD';
GRANT ALL PRIVILEGES ON DATABASE $AZ_DATABASE_NAME TO "$AZ_POSTGRESQL_NON_ADMIN_USERNAME";
EOF

Verwenden Sie dann den folgenden Befehl, um das SQL-Skript zum Erstellen des/der Microsoft Entra-Benutzers/-Benutzerin ohne Administratorrechte auszuführen:

psql "host=$AZ_DATABASE_SERVER_NAME.postgres.database.azure.com user=$AZ_POSTGRESQL_ADMIN_USERNAME dbname=$AZ_DATABASE_NAME port=5432 password=$AZ_POSTGRESQL_ADMIN_PASSWORD sslmode=require" < create_user.sql

Verwenden Sie nun den folgenden Befehl, um die temporäre SQL-Skriptdatei zu entfernen:

rm create_user.sql

Erstellen einer reaktiven Spring Boot-Anwendung

Zum Erstellen einer reaktiven Spring Boot-Anwendung wird Spring Initializr verwendet. Die von uns erstellte Anwendung verwendet Folgendes:

  • Spring Boot 2.7.11.
  • Die folgenden Abhängigkeiten: Spring Reactive Web (auch als Spring WebFlux bezeichnet) und Spring Data R2DBC.

Erstellen der Anwendung mithilfe von Spring Initializr

Generieren Sie die Anwendung mithilfe des folgenden Befehls in der Befehlszeile:

curl https://start.spring.io/starter.tgz -d dependencies=webflux,data-r2dbc -d baseDir=azure-database-workshop -d bootVersion=2.7.11 -d javaVersion=17 | tar -xzvf -

Hinzufügen der reaktiven PostgreSQL-Treiberimplementierung

Öffnen Sie die Datei pom.xml des generierten Projekts, um den reaktiven PostgreSQL-Treiber aus dem Repository „r2dbc-postgresql“ auf GitHub hinzuzufügen. Fügen Sie nach der Abhängigkeit spring-boot-starter-webflux den folgenden Text hinzu:

<dependency>
    <groupId>io.r2dbc</groupId>
    <artifactId>r2dbc-postgresql</artifactId>
    <version>0.8.12.RELEASE</version>
    <scope>runtime</scope>
</dependency>

Konfigurieren von Spring Boot für die Verwendung von Azure Database for PostgreSQL

Öffnen Sie die Datei src/main/resources/application.properties, und fügen Sie den folgenden Text hinzu:

logging.level.org.springframework.data.r2dbc=DEBUG

spring.r2dbc.url=r2dbc:pool:postgres://$AZ_DATABASE_SERVER_NAME.postgres.database.azure.com:5432/$AZ_DATABASE_NAME
spring.r2dbc.username=nonspring
spring.r2dbc.password=$AZ_POSTGRESQL_NON_ADMIN_PASSWORD
spring.r2dbc.properties.sslMode=REQUIRE

Ersetzen Sie die $AZ_DATABASE_SERVER_NAME, $AZ_DATABASE_NAMEund $AZ_POSTGRESQL_NON_ADMIN_PASSWORD Variablen durch die Werte, die Sie am Anfang dieses Artikels konfiguriert haben.

Warnung

Aus Sicherheitsgründen erfordert Azure Database for PostgreSQL die Verwendung von SSL-Verbindungen. Daher müssen Sie die Konfigurationseigenschaft spring.r2dbc.properties.sslMode=REQUIRE hinzufügen. Andernfalls versucht der R2DBC PostgreSQL-Treiber, eine unsichere Verbindung herzustellen, was zu einem Fehler führt.

Hinweis

Zur Verbesserung der Leistung ist die spring.r2dbc.url-Eigenschaft so konfiguriert, dass ein Verbindungspool mit r2dbc-pool verwendet wird.

Sie sollten Ihre Anwendung nun mithilfe des angegebenen Maven-Wrappers wie folgt starten können:

./mvnw spring-boot:run

Hier sehen Sie einen Screenshot der Anwendung bei der ersten Ausführung:

Screenshot of the running application.

Erstellen des Datenbankschemas

Konfigurieren Sie in der DemoApplication-Hauptklasse mit dem folgenden Code eine neue Spring Bean, die ein Datenbankschema erstellt:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.r2dbc.connectionfactory.init.ConnectionFactoryInitializer;
import org.springframework.data.r2dbc.connectionfactory.init.ResourceDatabasePopulator;

import io.r2dbc.spi.ConnectionFactory;

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Bean
    public ConnectionFactoryInitializer initializer(ConnectionFactory connectionFactory) {
        ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer();
        initializer.setConnectionFactory(connectionFactory);
        ResourceDatabasePopulator populator = new ResourceDatabasePopulator(new ClassPathResource("schema.sql"));
        initializer.setDatabasePopulator(populator);
        return initializer;
    }
}

Diese Spring Bean verwendet eine Datei namens schema.sql. Erstellen Sie daher diese Datei im Ordner src/main/resources, und fügen Sie den folgenden Text hinzu:

DROP TABLE IF EXISTS todo;
CREATE TABLE todo (id SERIAL PRIMARY KEY, description VARCHAR(255), details VARCHAR(4096), done BOOLEAN);

Halten Sie die ausgeführte Anwendung an, und starten Sie sie mit dem folgenden Befehl erneut. Die Anwendung verwendet nun die Datenbank demo, die Sie zuvor erstellt haben, und erstellt darin eine todo-Tabelle.

./mvnw spring-boot:run

Hier sehen Sie einen Screenshot der Datenbanktabelle während der Erstellung:

Screenshot of the creation of the database table.

Codieren der Anwendung

Fügen Sie als Nächstes den Java-Code hinzu, der R2DBC zum Speichern und Abrufen von Daten auf bzw. aus Ihrem PostgreSQL-Server verwendet.

Erstellen Sie neben der Klasse DemoApplication mit dem folgenden Code eine neue Todo-Java-Klasse:

package com.example.demo;

import org.springframework.data.annotation.Id;

public class Todo {

    public Todo() {
    }

    public Todo(String description, String details, boolean done) {
        this.description = description;
        this.details = details;
        this.done = done;
    }

    @Id
    private Long id;

    private String description;

    private String details;

    private boolean done;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getDetails() {
        return details;
    }

    public void setDetails(String details) {
        this.details = details;
    }

    public boolean isDone() {
        return done;
    }

    public void setDone(boolean done) {
        this.done = done;
    }
}

Bei dieser Klasse handelt es sich um ein Domänenmodell, das der zuvor erstellten todo-Tabelle zugeordnet ist.

Sie benötigen ein Repository, um diese Klasse zu verwalten. Definieren Sie mit dem folgenden Code eine neue TodoRepository-Schnittstelle im gleichen Paket:

package com.example.demo;

import org.springframework.data.repository.reactive.ReactiveCrudRepository;

public interface TodoRepository extends ReactiveCrudRepository<Todo, Long> {
}

Dieses Repository ist ein reaktives Repository, das von Spring Data R2DBC verwaltet wird.

Stellen Sie die Anwendung fertig, indem Sie einen Controller erstellen, der Daten speichern und abrufen kann. Implementieren Sie eine TodoController-Klasse im gleichen Paket, und fügen Sie den folgenden Code hinzu:

package com.example.demo;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
@RequestMapping("/")
public class TodoController {

    private final TodoRepository todoRepository;

    public TodoController(TodoRepository todoRepository) {
        this.todoRepository = todoRepository;
    }

    @PostMapping("/")
    @ResponseStatus(HttpStatus.CREATED)
    public Mono<Todo> createTodo(@RequestBody Todo todo) {
        return todoRepository.save(todo);
    }

    @GetMapping("/")
    public Flux<Todo> getTodos() {
        return todoRepository.findAll();
    }
}

Halten Sie die Anwendung schließlich an, und starten Sie sie mit dem folgenden Befehl erneut:

./mvnw spring-boot:run

Testen der Anwendung

Zum Testen der Anwendung können Sie cURL verwenden.

Erstellen Sie zunächst mit dem folgenden Befehl ein neues todo-Element in der Datenbank:

curl --header "Content-Type: application/json" \
    --request POST \
    --data '{"description":"configuration","details":"congratulations, you have set up R2DBC correctly!","done": "true"}' \
    http://127.0.0.1:8080

Mit diesem Befehl sollte das erstellte Element wie hier gezeigt zurückgegeben werden:

{"id":1,"description":"configuration","details":"congratulations, you have set up R2DBC correctly!","done":true}

Rufen Sie anschließend die Daten mithilfe einer neuen cURL-Anforderung mit dem folgenden Befehl ab:

curl http://127.0.0.1:8080

Mit dem folgenden Befehl wird wie hier gezeigt die Liste der „todo“-Elemente zurückgegeben, einschließlich des von Ihnen erstellten Elements:

[{"id":1,"description":"configuration","details":"congratulations, you have set up R2DBC correctly!","done":true}]

Hier sehen Sie einen Screenshot dieser cURL-Anforderungen:

Screenshot of the cURL test.

Herzlichen Glückwunsch! Sie haben eine vollständig reaktive Spring Boot-Anwendung erstellt, die R2DBC zum Speichern und Abrufen von Daten in bzw. aus Azure Database for PostgreSQL verwendet.

Bereinigen von Ressourcen

Um alle während dieser Schnellstartanleitung verwendeten Ressourcen zu sauber, löschen Sie die Ressourcengruppe mithilfe des folgenden Befehls:

az group delete \
    --name $AZ_RESOURCE_GROUP \
    --yes

Nächste Schritte

Weitere Informationen zum Bereitstellen einer Spring Data-Anwendung für Azure Spring Apps und die Verwendung verwalteter Identitäten finden Sie im Lernprogramm: Bereitstellen einer Spring-Anwendung in Azure Spring Apps mit einer kennwortlosen Verbindung zu einer Azure-Datenbank.

Weitere Informationen zu Spring und Azure finden Sie im Dokumentationscenter zu Spring in Azure.

Siehe auch

Weitere Informationen zu Spring Data R2DBC finden Sie in der Referenzdokumentation zu Spring.

Weitere Informationen zur Verwendung von Azure mit Java finden Sie unter Azure für Java-Entwickler und Working with Azure DevOps and Java (Arbeiten mit Azure DevOps und Java).